Shop OBEX P1 Docs P2 Docs Learn Events
How to run two cogs in Prop-2 assembly language? — Parallax Forums

How to run two cogs in Prop-2 assembly language?

I want to run a cog that transmits data and another cog that will independently receive the data and display it on LEDs. Think of two separate UARTs. I have no idea how to set up two independent cogs in assembly language for the Propeller 2 and would appreciate some sort of simple example that shows how to do it. Thank you. --Jon

Comments

  • SeairthSeairth Posts: 2,474
    edited 2020-06-13 18:56
    You will need to use COGINIT. Read over Starting and Stopping Cogs. There's also an example snippet in that section. There are examples of different ways of starting another cog. It's not quite what you need, but hopefully it will get you started.
  • After several hours or tests I have gotten nowhere trying to set up two cogs to run different tasks. The first task, sync_transmit works as expected. The second task, sync_receive, does not affect the LEDs. I have another short routine that simply turns the LEDs on and off--works fine. I just want to run code independently on two cogs. Here it seems the sync_receive code never runs. All help appreciated. --Jon

    CON
            clkout   = 20	  ' Pin P20
    	txout    = 21     ' Pin P21
    	rxin     = 31
            rxclkin  = 30
    	
    dat	
    	org
            coginit	#%100100, @sync_receive        ' init cog-4 for synchronous receive
    	coginit	#%100010, @sync_transmit       ' init cog-2 for synchronous transmit 
            
    '====================================
    		
    sync_transmit
            dirl    #txout
            wrpin	sync_tx_mode,     #txout        'Set up sync tx mode for pin 21
    	wxpin	#%1_00111,        #txout	'Set up stop/start mode, X[5] = 1, 8 bits
    	dirh	#txout			        'Enable Smart Pin
    	
    	dirl    #clkout
            wrpin	clock_mode,       #clkout       'Set pin P20 as transition-output mode
    	wxpin	##$1000,          #clkout        'Set base period for transition output
    	dirh	#clkout                         'Enable P20 as clock-output
    
    .loop	waitx	##10_000_000			'Delay between transmissions
    	wypin	#$85,             #txout        '8-bit data to transmit: 10000101
    	wypin	#16,              #clkout       'Start clock, transmit data
    	
    	jmp	#.loop
    
    '====================================
    
    sync_receive       
    	 mov dira, ##$FF		' Pins P7--P0 for output
             mov outa, my_test_data		    	'just a test
    .dummy	nop
    	jmp #.dummy
    
                             
    sync_tx_mode    long  %0000_0111_000_0000000000000_01_11100_0
    
    clock_mode	long  %0000_0000_000_000000_1_000000_01_00101_0
    
    sync_rx_mode    long  %0111_0000_000_0000000000000_00_11101_0
    
    my_test_data	long	$55
    


  • SeairthSeairth Posts: 2,474
    edited 2020-06-13 23:25
    Two things I notice right away:
    * You don't need the second COGINIT because cog 1 will keep executing after the COGINITs. In fact, it's likely cog 1 that's running your transmit code, not cog 2 (for the same reason that receive isn't working).
    * For each block of code you are going to run in cogexec mode with COGINIT, you should have an ORG 0 at the beginning of the block.
  • Cluso99Cluso99 Posts: 18,069
    This code starts an unused cog with the cogid value returned in the D (id) register
    '+-------[ Start SD Driver COG code ]------------------------------------------+
                mov     id,         #16                 ' start next cog avail and return cogid
                setq    ##sd_mailbox                    ' put in PTRA of started cog
                coginit id,         ##@sddriver     wc  ' starts a free cog, returns cogid (id=16 initially)
    '+-----------------------------------------------------------------------------+
    
    and here is how you load LUT in the current cog
    '+-------[ Load LUT code ??? ]-------------------------------------------------+
                  setq2     ##_USER_LUT_END-_USER_LUT_BEGIN-1 '\ load LUT
                  rdlong    0, ##_USER_LUT_BEGIN              '/
    
  • Seairth wrote: »
    Two things I notice right away:
    * You don't need the second COGINIT because cog 1 will keep executing after the COGINITs. In fact, it's likely cog 1 that's running your transmit code, not cog 2 (for the same reason that receive isn't working).
    * For each block of code you are going to run in cogexec mode with COGINIT, you should have an ORG 0 at the beginning of the block.

    Ok. I had a bit more time to look over the code this morning. A few suggestions:
    • Change the first COGINIT to "COGINIT #%0_0_0100, #@sync_receive". This will cause the newly-started cog to execute in cogexec mode. It will start by loading its registers from the specified hub address. (note: if the code you are loading from is at an address greater than hub address $1FF, then you will need to use ## instead.)
    • Remove the second COGINIT. As I mentioned before, the current cog (0) will execute the transmit code after it's issued the command to start the other cog. No need to start a third cog in this case.
    • In front of the sync_receive code block, add "ORG 0". This will ensure that the calculated addresses for the following code will be correct. Recall that the COGINIT will copy this code into its registers starting at $000 and start execution at $000, so you need to make sure the addresses in the code are calculated relative to that same address.
  • Thanks, guys. Not much progress. I followed your suggestions. Now when I run the code below, the LEDs turn on, but the serial transmit does not work. If I comment out the coginit instruction and all the code for the sync_receive, no LEDs, but I can see the proper sync-output signals on my scope. Seems like an either-or situation. Any reason why the P2 wouldn't continue with the sync-serial transmit after it starts cog 4? I thought there might be an I/O conflict, so I moved the sync clock to pin 40 and the sync data-out to pin 41. Same results. Each routine works, but they seem unable to run simultaneously in two cogs. Beats me. --Jon
    CON
            clkout   = 40	  ' Pin P40
    	txout    = 41     ' Pin 41
    	rxin     = 31
            rxclkin  = 30
    	
    dat	
    	org 0      
            coginit	#%0_0_0100, ##@sync_receive        ' init cog-2 for synchronous receive
    	       
    '====================================
    ' Sync-serial transmit
    		
            dirl    #txout
            wrpin	sync_tx_mode,     #txout        'Set up sync tx mode for pin 21
    	wxpin	#%1_00111,        #txout	'Set up stop/start mode, X[5] = 1, 8 bits
    	dirh	#txout			        'Enable Smart Pin
    	
    	dirl    #clkout
            wrpin	clock_mode,       #clkout       'Set pin P20 as transition-output mode
    	wxpin	##$1000,          #clkout        'Set base period for transition output
    	dirh	#clkout                         'Enable P20 as clock-output
    
    .loop	waitx	##10_000_000			'Delay between transmissions
    	wypin	#$85,             #txout        '8-bit data to transmit: 10000101
    	wypin	#16,              #clkout       'Start clock, transmit data
    	
    	jmp	#.loop
    
    '====================================
    	
    sync_receive
             org 0
         	 mov dira, ##$00FF		' Pins P7--P0 for output
             mov outa, my_test_data		    	'just a test
    .dummy	 nop
    	 jmp #.dummy
    
                             
    sync_tx_mode    long  %0000_0111_000_0000000000000_01_11100_0
    
    clock_mode	long  %0000_0000_000_000000_1_000000_01_00101_0
    
    sync_rx_mode    long  %0111_0000_000_0000000000000_00_11101_0
    
    my_test_data	long	$55
    
  • Cluso99Cluso99 Posts: 18,069
    Try this...
    It should start cog 1 (first free cog) and return the cogid of the started cog into id. If it works then output id to the pins instead of $55 to see that it did indeed start cog 1.
    CON
            clkout   = 40	  ' Pin P40
    	txout    = 41     ' Pin 41
    	rxin     = 31
            rxclkin  = 30
    	
    dat	
    	org 0      
    '        coginit	#%0_0_0100, ##@sync_receive        ' init cog-2 for synchronous receive
            coginit	id, ##@sync_receive wc       ' init cog-2 for synchronous receive
    	       
    '====================================
    ' Sync-serial transmit
    		
            dirl    #txout
            wrpin	sync_tx_mode,     #txout        'Set up sync tx mode for pin 21
    	wxpin	#%1_00111,        #txout	'Set up stop/start mode, X[5] = 1, 8 bits
    	dirh	#txout			        'Enable Smart Pin
    	
    	dirl    #clkout
            wrpin	clock_mode,       #clkout       'Set pin P20 as transition-output mode
    	wxpin	##$1000,          #clkout        'Set base period for transition output
    	dirh	#clkout                         'Enable P20 as clock-output
    
    .loop	waitx	##10_000_000			'Delay between transmissions
    	wypin	#$85,             #txout        '8-bit data to transmit: 10000101
    	wypin	#16,              #clkout       'Start clock, transmit data
    	
    	jmp	#.loop
    
    '====================================
    	
    sync_receive
             org 0
         	 mov dira, ##$00FF		' Pins P7--P0 for output
             mov outa, my_test_data		    	'just a test
    .dummy	 nop
    	 jmp #.dummy
    
                             
    sync_tx_mode    long  %0000_0111_000_0000000000000_01_11100_0
    
    clock_mode	long  %0000_0000_000_000000_1_000000_01_00101_0
    
    sync_rx_mode    long  %0111_0000_000_0000000000000_00_11101_0
    
    my_test_data	long	$55
    id long 16
    
  • Cluso99Cluso99 Posts: 18,069
    Think your problem may be
    sync_receive needs to be moved after the cog 0. It would otherwise be getting the address in cog just after the jmp #.loop instruction. ie its int the wrong cog space.
  • Cluso99 wrote: »
    Think your problem may be
    sync_receive needs to be moved after the cog 0. It would otherwise be getting the address in cog just after the jmp #.loop instruction. ie its int the wrong cog space.

    That shouldn't matter here because it's the hub address of sync_receive that he needs, right?
  • SeairthSeairth Posts: 2,474
    edited 2020-06-15 02:21
    JonTitus wrote: »
    Thanks, guys. Not much progress. I followed your suggestions. Now when I run the code below, the LEDs turn on, but the serial transmit does not work. If I comment out the coginit instruction and all the code for the sync_receive, no LEDs, but I can see the proper sync-output signals on my scope. Seems like an either-or situation. Any reason why the P2 wouldn't continue with the sync-serial transmit after it starts cog 4? I thought there might be an I/O conflict, so I moved the sync clock to pin 40 and the sync data-out to pin 41. Same results. Each routine works, but they seem unable to run simultaneously in two cogs. Beats me. --Jon

    Ok, so when you added the second "ORG 0", you reset the cog address counter, including for "sync_tx_mode" and "clock_mode". Simply move them above "sync_receive" (technically, above the second "ORG 0"), so that their addressing is relative to the first block of cog code.

    Also, I recommend following @Cluso99's advice about dynamically allocating the receive cog. As you re-use code snippets, this keeps you from having to manually adjust cog allocation.
  • Cluso99Cluso99 Posts: 18,069
    Seairth wrote: »
    Cluso99 wrote: »
    Think your problem may be
    sync_receive needs to be moved after the cog 0. It would otherwise be getting the address in cog just after the jmp #.loop instruction. ie its int the wrong cog space.

    That shouldn't matter here because it's the hub address of sync_receive that he needs, right?
    No. You're right. It is picking up the hub address. I looked at the listing from fastspin just to be sure :)
    Later this afternoon I discovered something similar with loading LUT. A few gotchas around placing the labels in the right position for it to work properly.
  • Many thanks, folks. The software runs. I include it below so others can see the final, working version. I'd be flailing around for days without help from you and others on this Forum --Jon
    ' Synchronous serial transmission, Rev. 3, 06-13-2020 at 1007 MDT
    'positive edge-trigger (Jon Titus)
    
    CON
            clkout   = 40	  ' Pin P40
    	txout    = 41     ' Pin 41
    	rxin     = 31
            rxclkin  = 30
    	
    dat	
    	org 0      
            coginit	id, ##@sync_receive        ' init cog-2 for synchronous receive
    	       
    '====================================
    ' Sync-serial transmit
    		
            dirl    #txout
            wrpin	sync_tx_mode,     #txout        'Set up sync tx mode for pin 21
    	wxpin	#%1_00111,        #txout	'Set up stop/start mode, X[5] = 1, 8 bits
    	dirh	#txout			        'Enable Smart Pin
    	
    	dirl    #clkout
            wrpin	clock_mode,       #clkout       'Set pin P20 as transition-output mode
    	wxpin	##$1000,          #clkout        'Set base period for transition output
    	dirh	#clkout                         'Enable P20 as clock-output
    
    
    .loop	waitx	##10_000_000			'Delay between transmissions
    	wypin	#$85,             #txout        '8-bit data to transmit: 10000101
    	wypin	#16,              #clkout       'Start clock, transmit data
    	
    	jmp	#.loop
    
    sync_tx_mode    long  %0000_0111_000_0000000000000_01_11100_0
    
    clock_mode	long  %0000_0000_000_000000_1_000000_01_00101_0
    
    id	        long 16
    '====================================
    	
    
             org 0
    sync_receive  	 mov dira, ##$00FF		' Pins P7--P0 for output
             mov outa, my_test_data		    	'just a test
    .dummy	 nop
    	 jmp #.dummy
    
    sync_rx_mode    long  %0111_0000_000_0000000000000_00_11101_0
    
    my_test_data	long	$81
    
    
  • I just posted an example in the "Customer Projects" section that demonstrates how to use the synchronous transmitter and receiver, using two cogs. Thank you all for your help. I am grateful. --Jon
  • JonTitus wrote: »
    I just posted an example in the "Customer Projects" section that demonstrates how to use the synchronous transmitter and receiver, using two cogs. Thank you all for your help. I am grateful. --Jon

    I'm glad you were able to get it working! Is this your first multi-cog program? I still remember my feeling of elation the first time I went multi-cog. Admittedly, that was on the P1, but that feeling has never really diminished.
  • Hi, Seairth. I programmed multiple cogs in SPIN in a book I wrote and Parallax made available for free (https://www.parallax.com/comment/111) in 2014-2015. It was a lot of fun and a cool thing to run several independent processors in one chip, also on the P1. The P2 is a lot more complicated and I never programmed the P1 in assembly language, so it is all new. For me it was a good feeling to get the synchronous transmit-receive program to work! --Jon
Sign In or Register to comment.