Shop OBEX P1 Docs P2 Docs Learn Events
Trouble getting a cog to work — Parallax Forums

Trouble getting a cog to work

I'm still playing with the LED&KEY module and making headway. I'm now trying to put the display part of the code in a separate cog to run continuously, displaying whatever the main cog has to display. The display part works great when part of the main cog but does not when put in its own cog.
This works
CON  '4th try. Displays value without zeros to left of significant digits. 
  _clkmode = xtal1 + pll16x                                               
  _xinfreq = 5_000_000

  DIO_PIN = 24
  CLK_PIN = 25
  STB_PIN = 26

 
OBJ
  tv : "tv_text"  
VAR
  byte DIN[4],counter   'not used in this iteration  
  long myStack[50]
  long displayValue
  long myValue,digpos,divisor
 
    
PUB main  
  tv.start(0)
  
  dira[DIO_PIN] := 1
  dira[CLK_PIN] := 1
  dira[STB_PIN] := 1
  outa[STB_PIN] := 1
  outa[CLK_PIN] := 1 
  
  DisplayValue:=83      'value to display
    
  divisor:=1
  
  tv.move(3,3)
  tv.str(string("divisor =  "))         'show current divisor
  tv.dec(divisor)
  
  clear  'start with clean registers
  
    repeat  digPos from 0 to 7   'right to left digit display
    
      tv.move(1,1)
      tv.str(string("digpos "))     'show current digit position if wait is long enough to see
      tv.dec(digpos)
      
      start 
      send_byte($8f) 'turn on bright
      end
       
      start
      send_byte($40)
      end
       
      start        
      send_byte(digSel[0 + digPos])       'enable the next digit
                     
      send_byte(Digits[0 + DisplayValue / divisor // 10])     'display the digit
      
      tv.move(2,2)
      tv.str(string("digit  "))
      tv.hex(Digits[0 + DisplayValue / divisor // 10],2)  'show hex value of digit
      
      waitcnt (clkfreq /100000+ cnt)   'time between repeat loops. Normally 1/100,000. Slow to 2 seconds to read TV
      end

      IF  divisor * 10 > displayValue     'No zeros left of msd
        quit
       
      
      divisor *= 10   'to display next ms digit
      
      tv.move(3,3)
      tv.str(string("divisor =  "))
      tv.dec(divisor)
      
  

DAT  '            0          1          2          3          4          5          6           7
  digits BYTE %00111111, %00000110, %01011011, %01001111, %01100110, %01101101, %01111101, %00000111,{
                  $3F        $06       $5B        $4F         $66        $6D        $7D        $07

  '    8          9
  }%01111111, %01101111
  '   $7F         $6F
  
  digsel byte $CE, $CC, $CA, $C8, $C6, $C4, $C2, $C0

This does not. I've used cogs before many times but this must be something unique. They are the same in every other respect.
The TV shows the cog as number 3
OBJ
    tv : "tv_text"
VAR
  byte DIN[4],counter   'not used in this iteration  
  long myStack[50]  
  long myValue, runningCogID  
    
PUB main

  tv.start(0)   
  dira[DIO_PIN] := 1
  dira[CLK_PIN] := 1
  dira[STB_PIN] := 1
  outa[STB_PIN] := 1
  outa[CLK_PIN] := 1
  
  runningCogID := cognew(ShowValue, @myStack) + 1
  wait1
  tv.str(string("cog = "))
  tv.dec(runningCogID)
  wait1
  repeat
    myValue:=46890      'value to display
PUB ShowValue | divisor, digpos, displayValue
  clear   'clear display
  Repeat
    displayValue:=myValue
    divisor:=1
    
    repeat  digPos from 0 to 7   'right to left digit display          
      start 
      send_byte($8f) 'turn on bright
      end
       
      start
      send_byte($40)
      end
       
      start        
      send_byte(digSel[0 + digPos])       'enable the next digit
                     
      send_byte(Digits[0 + DisplayValue / divisor // 10])     'display the digit    
      
      waitcnt (clkfreq + cnt)   'time between repeat loops. Normally 1/100,000. Slow to 2 seconds to read TV
      end
     
      IF  divisor * 10 > displayValue     'No zeros left of msd
        quit     
      divisor *= 10   'to display next ms digit  

Thanks
Aaron

Comments

  • RaymanRayman Posts: 14,640
    You need to move this stuff:
      dira[DIO_PIN] := 1
      dira[CLK_PIN] := 1
      dira[STB_PIN] := 1
      outa[STB_PIN] := 1
      outa[CLK_PIN] := 1
    

    To the code for the new cog...
  • Ah! Thanks Rayman.
    I had tried that but left it in both cogs thinking that the send_byte and other methods needed it also in the main cog. I guess not!
    Aaron
  • JonnyMacJonnyMac Posts: 9,102
    edited 2019-12-03 03:05
    The cog controlling IO pins needs to set them up, and other cogs should clear those DIRx bits for those pins to prevent interference. If one cog makes a pin output+high and another cog wants to make it output+low, the second cog loses. The reason is that the cog outputs are OR'd together before the final output. If any cog makes a pin and output+high, that's what you're going to get on the physical IO pin.
  • RaymanRayman Posts: 14,640
    It's often best to have driver code in it's own spin file, to avoid things like this...

    Just like the TV driver does, the main spin file passes the pin numbers needed to that file...
  • Rayman wrote: »
    It's often best to have driver code in it's own spin file

    Just like the TV driver does, the main spin file passes the pin numbers needed to that file...

    So do you mean a separate object in the library to be called by top object. I've made a few simple ones of those and saved them in the library.

    Aaron

  • RaymanRayman Posts: 14,640
    Yes. Personally, I like to define all the pin numbers to be used in the top object and then pass them to sub objects.
    Normally, I put a "Start" function in the sub-objects that receives the pin numbers and starts up any cogs needed.
  • JonnyMacJonnyMac Posts: 9,102
    edited 2019-12-04 00:46
    I'm now trying to put the display part of the code in a separate cog to run continuously

    That really shouldn't be a problem. I frequently do this with a background cog that spits out continuous debugging information to a terminal. It seems like the code you've submitted here is not complete, because the IO pins in your listing are never used.

    I'm with Ray on these points:
    -- Define your project pin numbers at the top of the program code. I put { I }, { O }, or { IO } comments on each pin definition line.
    -- Generic objects should go into a separate file so they can be shared.

    Specialty objects can be embedded, so long as you follow the rules that have been outlined about pin use. The advantage of an embedded Spin object is that it can access the objects defined by the application, so long as you don't have a conflict with the top-level code (e.g., you don't want to your main code and background code sending values to the TV object).

    There is another case for embedded Spin cogs: When the project has specific hardware that makes that code specific -- not useful to other projects by placing in an external file. I have attached my template file for the EFX-TEK HC-8+ controller. I designed the HC-8+ circuit for EFX-TEK. In the main code you'll see there is a background Spin cog that refreshes a bunch of inputs (through shift registers), manages a red/green LED so that it can be red, green, yellow, or off, and flash between any two colors. Finally, it keeps track of a 1m-resolution timer that can be used for long events. This background Spin code is often modified for specific projects. Most don't use the RG LED. I have a few that need simple, monotonic music, so there is a version that can do that.

    Finally, in the case for generic objects... last week I went through the exercise of removing numeric formatting routines built into display objects (like FullDuplexSerial, serial LCDs, I2C LCDs) that have a .str() (string output) method. Any device that wants to display formatted numbers can use an object called jm_format.spin (which originated at Parallax; I have made heavy updates). In fact, if i ever decide to use TV_Text, I will update it to use the jm_format.spin. You could either add this to TV_Text, or you could add it to your main app and then remove the formatting code from your background cog. That might look like this.
    pri show_value | last                                           ' background cog!
    
      last := negx                                                  ' force immediate update
    
      repeat
        if (myValue <> last)                                        ' change in foreground?
          last := myValue                                           ' save change
          ' move to first position of field
          tv.str(fmt.rjdec(last, 8, " "))                           ' right justified decimal
    

    Final note: You'll see that I define by embedded Spin cogs as private methods. In the top level object, there really is no such thing as a private method -- this just serves to remind me not to call that code like a standard method.
  • Jon
    I've admired your coding for a long time but lots of it is beyond my skill level.
    Aaron
Sign In or Register to comment.