Shop OBEX P1 Docs P2 Docs Learn Events
INA & OUTA control — Parallax Forums

INA & OUTA control

JBWolfJBWolf Posts: 405
edited 2011-10-23 03:59 in Propeller 1
I'm having trouble launching 2 cogs that each monitor a set of pins with pushbuttons on them.

In one cog it monitors the 2 input pins and flashes an LED if one is pressed.
The other cog increments or decrements variables depending on which button is pressed.

In the beginning of each PUB being launched I have declared the pins and variables before use.
But as soon as I launch the second cog, it stops working

This is in each method being launched:
dira[20..21]~ ' Set Buttons to input
outa[20..21]~
dira[LED]~~ 'used in cog2 only

In cog 1 I am basically using this:
repeat
if ina[20] == 1
value := ++ value

In cog 2 I am using this:
repeat
if ina[20] == 1
outa[LED]~~

Comments

  • Heater.Heater. Posts: 21,230
    edited 2011-10-18 03:56
    Be aware that there is a separate DIRA and OUTA register for each COG.

    So if one COG sets DIRA as output that does not have any effect for the other COGS.
    Every COG that wants to output on some pins must have it's own DIRA statement to set those pins to output.

    Also every COG can write to the same pin for OUTA. The actual output on the pin will be the logical OR of what is written.
    So basically if any COG sets a pin to 1 the output will be high.
  • MagIO2MagIO2 Posts: 2,243
    edited 2011-10-18 04:01
    You should always post the original unmodified code. Chance is pretty high that you cut out the part which is causing problems.

    As INA always works (even if the PIN is set to output it gives you the state of the PIN) it must be elsewhere.
    Is LED maybe defined as PIN 20 as well?

    Oh ... wait a minute:
    When saying this is in each method do you really mean that you set the LED-Pin to output in both COGs? You should only define PINs as output in the COG that's really using it!
  • max72max72 Posts: 1,155
    edited 2011-10-18 05:15
    As an add on to Heater's comment:
    Check the manual, chapter 1, I/O PINS.
    In revision 1.2 of the manual it is at page 26-27.

    Massimo
  • frank freedmanfrank freedman Posts: 1,983
    edited 2011-10-18 10:59
    JBWolf wrote: »
    I'm having trouble launching 2 cogs that each monitor a set of pins with pushbuttons on them.

    In one cog it monitors the 2 input pins and flashes an LED if one is pressed.
    The other cog increments or decrements variables depending on which button is pressed.

    In the beginning of each PUB being launched I have declared the pins and variables before use.
    But as soon as I launch the second cog, it stops working

    This is in each method being launched:
    dira[20..21]~ ' Set Buttons to input
    outa[20..21]~
    dira[LED]~~ 'used in cog2 only

    In cog 1 I am basically using this:
    repeat
    if ina[20] == 1
    value := ++ value

    In cog 2 I am using this:
    repeat
    if ina[20] == 1
    outa[LED]~~


    Just out of curiosity (or I need to go back to the book) why does the code set the direction of 20/21 to input and then try to set those pins to low using an output statement? Will this value override the actual pin input?

    Frank
  • JBWolfJBWolf Posts: 405
    edited 2011-10-18 13:49
    If I remark out the 'lasercontrol' and 'pwrflash' commands so they are not used.... the 'laserdriver' and 'scan' work fine.
    With everything in place, nothing runs at all, looks like it locks up.
    Still locks up if I remark out every 'outa[20..21]~'

    {{
      Simple Scan Test w/ Buttons & LED
    
      motor 1 = pins 8-11   = Y Axis - ++stp = Y Down
      motor 2 = pins 12-15  = X Axis - ++stp = X Left
    
      Launch buttons & Laser into new cog, run motors in main, use globals for button changes
    }}
    
    
    CON
       
      _clkmode = xtal1 + pll16x                  ' System clock → 80 MHz
      _xinfreq = 5_000_000
    
      LaserPin = 16
      B1 = 20
      B2 = 21
      ILED = 26   
      PLED = 27
    
              
    VAR
      long stack[4000]                        ' Cog stack space
      byte cog[4]                             ' Cog ID
      long laser
    
      
    
    PUB Main | button1
    laser := 0
    
    Launchcogs
    repeat
    
    
    
    
    PUB LSRControl(lsraddr)
    dira[20..21]~                             ' Set Buttons to input
    outa[20..21]~                             ' Turn input ON
    waitcnt(clkfreq * 3 + cnt)
    repeat
      if ina[20] == 1
         long[lsraddr] := 0
      if ina[21] == 1
         long[lsraddr] := 1
      
    
    
    
      
    PUB LaunchCogs
      cognew(PwrFlash, @stack[1000])        ' Start button flash
      cognew(laserdriver(@laser), @stack[2000])      ' Start Laser
      cognew(scan(@laser), @stack[3000])     ' Start motor scans
      cognew(LSRControl(@laser), @stack[4000])        ' Start laser buttons
    
    PUB PwrFlash
    dira[20..21]~                             ' Set Buttons to input
    outa[20..21]~                             ' Turn input ON
    dira[26..27]~~                            ' Set LED's to output
      
    repeat    
        if ina[B1]  == 1  or ina[b2] == 1      
           outa[PLED]~
        else
           outa[PLED]~~
    
           
    PUB LaserDriver(LaserAddr)
    dira[LaserPin]~~         ' Laser output
    outa[LaserPin]~          ' Laser OFF
    
    
    repeat  
       if long[laseraddr] == 1
         outa[LaserPin]~~ 
       if long[laseraddr] == 0
         outa[LaserPin]~
    
    
    
      
    PUB Scan(laseraddr) | stp, stpx, stpy
    stp := 0
    stpx := 0
    stpy := 0
    
    dira[8..11]~~
    dira[12..15]~~      ' X&Yaxis Motors
    
     repeat 65                                     ' Start Calibrate
       outa[12..15] := WStep[stp]
       outa[8..11] := WStep[stp] 
       waitcnt((clkfreq / 200) + cnt)
       stp := stp + 1
        if stp == 4
           stp := 0
    
     repeat 24
       outa[12..15] := WStep[stp]
       outa[8..11] := WStep[stp]  
       waitcnt((clkfreq / 200) + cnt)
       stp := stp - 1
         if stp == -1
            stp := 3                               ' End Calibrate
    
    stpx := (stp * 2) + 1               
    stpy := (stp * 2) + 1                          ' Set to Hstep mode
    
    waitcnt(clkfreq * 2 + cnt)                     ' 2sec pause
    long[laseraddr] := 1                           ' Laser ON
                                                   ' -= Start Motor Scan =-
        repeat 8                                   ' Move to start position up/left 5
          stpx := stpx + 1
          if stpx == 8
             stpx := 0
          outa[12..15] := HStep[stpx]  
          waitcnt(clkfreq / 1500 + cnt)
    
          stpy := stpy - 1
          if stpy == -1
             stpy := 7
          outa[8..11] := HStep[stpy]  
          waitcnt(clkfreq / 1500 + cnt)
    
        repeat
           repeat 16
              stpx := stpx - 1
              if stpx == -1
                 stpx := 7
             outa[12..15] := HStep[stpx]  
             waitcnt(clkfreq / 1000 + cnt)
    
           repeat 16
             stpx := stpx + 1
             if stpx == 8
                stpx := 0
             outa[12..15] := HStep[stpx]  
             waitcnt(clkfreq / 1000 + cnt) 
    
    
       
    PUB Pause(dly)
      Waitcnt(clkfreq / dly + cnt)
    
    PUB MPause(dly)
      Waitcnt(clkfreq * dly + cnt) 
    
    
    
    
    DAT
    
    HStep   byte   %1001, %1000, %1100, %0100, %0110, %0010, %0011, %0001   ' Half Step - best resolution
    FStep   byte   %1001, %1100, %0110, %0011                               ' Full Step - max torque
    WStep   byte   %1000, %0100, %0010, %0001                               ' Wave Step - weak torque
    
  • JBWolfJBWolf Posts: 405
    edited 2011-10-18 14:04
    Mag:
    I need 2 cogs to EACH control the same 2 buttons is whats really going on.
    I have 2 LED's, one is for power, the other as a mode indicator.
    If you press any button, it flashes the power LED just to show you it did recognize the button being pressed. Depending on which button is pressed, it will change the variable for turning the laser on or off.

    So if you look in the PwrFlash method... this keeps the power light on and flashes if a button is being pressed.
    In the LSRControl method, if button 1 is pressed, the laser variable gets turned to 0, which shuts off the laser. If button 2 is pressed, it will turn back on.

    Seems to me there is a control conflict while using two INA[] statements in two different cogs.
    Only thing I can think of doing is removing the PwrFlash method, using the Main method to initially turn on the power LED... then in the 'LSRControl' method, use !outa[PLED] with a delay, then another ! to turn it back on.
    This way I could still get the flash while keeping all button and LED control in the same cog.

    I would like to know how to receive button input from 2 different cogs at the same time
  • JBWolfJBWolf Posts: 405
    edited 2011-10-18 14:38
    I got it to work by keeping all the button and LED control in the same cog.
    I think I might be able to get everything done I need to with the buttons in one cog... but it shure would be nice to be able to check a button status from another cog
  • MagIO2MagIO2 Posts: 2,243
    edited 2011-10-18 15:51
    Again: It's no problem to use INA in several COGs!

    Don't know if this is the only problem, but this is a bad idea:
    cognew(LSRControl(@laser), @stack[4000])

    The stack is only 4000 longs big. I think you are used to stacks in other microcontrollers, but the stack in the propeller does not grow top to bottom! It's bottom up!
    So, in the code you posted you should subtract 1000 from each stack-pointer.

    1000 longs is a very big stack. With 4000 longs you already used 4000*4 = 16kByte of RAM, which is half of the RAM available.

    You don't need the DIRA~ and OUTA~ statements. All pins are per default inputs.

    PUB PwrFlash
    should only set pin 27 to output, as this is the only pin used by the function.
  • Cluso99Cluso99 Posts: 18,069
    edited 2011-10-18 16:06
    As Magio2 said, you do not need to set DIRA~ and OUTA~ statements for inputs as this is the default. You cannot override using and OUTA~~ statement if the pin is an input. This just prepares the output ready so you do not necessarily get a glitch (really depends on the app - sometimes this is used with pullups to run a wired or circuit).

    I would start with something smaller.. Take your code and just have 1 cog sampling the 2 input pins like you have. Have a second cog taking those hub variables and setting led(s). When this works, add another cog to take the hub variable and set the laser (presume you are ust using an led to indicate this for now). Build your code up with little cogs, one at a time. You will be amazed at how simple this seems, and any problems are so much easier to find. Otherwise, you are looking for a needle in a haystack, and of course there may be more than one needle!
  • JBWolfJBWolf Posts: 405
    edited 2011-10-19 22:24
    Yes I know 1000 was way too many... but it was enough that I knew for sure that the stack would never be a problem... as taught in the PE book

    I have now completed the program... but I was never able to use outa to the same pins from more than one cog.
    A good example of this.... The 'Scan' method in the above code declares dira[8..11]~~ and uses those pins just one time with outa during what is remarked as 'calibrate'. I later tried in another cog a very VERY simple test by manually setting the next step for the outa[8..11] (made absolutely sure what the next step is and completely avoided using global or local variables to eliminate conflicts or incorrectly used longs). It absolutely will not go to the next proper step from another cog... I dont know if the last outa from the 'calibrate' is still active in that cog or what... but it is impossible to make a proper movement using outa[8..11] in another cog. I tried every single way I could think of. I'm betting it is caused because the outa[8..11] in the 'scan' method cog is still active until I turn it off with something like %0000... so the new cog is actively fighting the other cog as they are both trying to set outa[8..11] at the same time.
    I believe the proper way to do this is to declare a new cog dedicated just to setting specific outa pins with global variables, then changing the global variable within other 'control' methods/cogs... rather than having a 'control' cog with the outa pin declarations inside it, this way it does not matter what cog is trying to use it because they are all writing to a global variable rather than raw outa[]. Or by only using outa in a 'control' method/cog that is 100% dedicated to those pins, no other methods or cogs can use those pins with outa

    The way I did get it to work, each cog is dedicated to certain pins... no other cog will ever try to use them. Otherwise I get incredibly unpredictable results or a complete lockup.
    I even came up with a very easy way to enter a menu system by pressing buttons, and if another button hasnt been pressed within 10 seconds of the last, it will exit the menu system... if a button is pressed, not only does it restart the 10 sec counter, it accurately records the button pressed.
    The PE book only shows how to keep good timing by using a waitcnt and adding the current count to the clkfreq, then waiting for that to expire.
    i.e. 1 second:
    dT := clkfreq
    T := cnt
    waitcnt(dT + T)
    ++second
    This will miss everything that has happened within that second.
    To use this method, you would basically have to launch a 'clock' in a new cog, then retrieve the current time to compare against later... way too much work.
    I'm not liking some of the basic principals of coding structure taught in the PE book.
    It was a real AHA! moment when I figured out a way around this
  • Cluso99Cluso99 Posts: 18,069
    edited 2011-10-20 00:06
    JBWolf: It is quite simple. If more than one cog has the same pin as an output, the output will be the "OR" of both values. There is no hardware conflict, it is just "OR"ed within the chip by OR gates. So if you like, all 8 cogs have their outputs for each pin ORed together and each OR is gated with the DIR value.

    With regard to the waitcnt, this just makes the core sit idle and consume little power while waiting for the count to expire. Nothing complex about this... it is doing nothing so cannot possibly see anything on pins. There are other ways to use cnt if you need to do other things while waiting. Dont forget to also look at waitpeq and waitpne too.
  • MagIO2MagIO2 Posts: 2,243
    edited 2011-10-20 02:28
    Oh ... now you talk about OUTA.
    If you want to use the same PINs in different COGs you have to make sure that the active COG is taking over the last state of the inactive COG and then set OUTA to 0 in the inactive COG. This is what I did in a DMA-like driver ;o) I have a graphics display which of course needs to be filled with some graphics-data. When reading a picture from SD-card, I let the SD-card driver (FSRW) takeover the control of the display I/Os. This way it can simply send the data directly to the display.

    Let's say you have a bus where different kind of devices are attached to, it could also make sense to have a central I/O controller COG which simly watches one or more HUB-RAM locations and send those values to the BUS. The drawback here is that it changes/slows down the timing constantly, whereas the takeover-concept only slows down for the takeover - which is very fast.
    cognew(LSRControl(@laser), @stack[4000])

    The stack is only 4000 longs big. I think you are used to stacks in other microcontrollers, but the stack in the propeller does not grow top to bottom! It's bottom up!

    Hope you recognized this part of my previous post. It's very important!
    With @stack[4000] you already point behind the stack variable, as the allowed indexes are 0 - 3999. So, with this cognew you immediately overwrite whatever is behind stack. In your example I'd guess that you overwrite the stack of the initial COG which is using all remaining HUB-RAM. Especially the return-address of the initial-COG is in danger in this case, as your cognews are running in a function. So, when the function is done, your initial COG can end up anywhere, doing nasty things.

    For input it also might make sense to have a COG that watches the I-PINs and dispatch the input to different HUB-RAM locations. As already mentioned the waitpne can wait for any change of the input-PINs. If you press one button you set a flag here, if you receive an impulse coming from a key matrix you store the value in a input-ring-buffer .... whatever you need. Of course you can even to similar things as in common operating-systems like implementing a event queue ...
  • Heater.Heater. Posts: 21,230
    edited 2011-10-20 03:31
    Let me reiterate,

    Be aware that there is a separate DIRA and OUTA register for each COG.

    So if one COG sets DIRA as output that does not have any effect for the other COGS.
    Every COG that wants to output on some pins must have it's own DIRA statement to set those pins to output.

    Also every COG can write to the same pin for OUTA. The output on the actual pin will be the logical OR of what is written to OUTA registers by the various COGS involved.
    So basically if any one COG sets a pin to 1, the output will be high even if all the others are setting the same pin to 0 (low).
  • JBWolfJBWolf Posts: 405
    edited 2011-10-20 16:11
    Cluso:
    Ah, if it is being OR'd, that would explain why I am getting such unpredictable results!
    Thanks, I will check out waitpeq and waitpne

    Mag:
    you are directly contradicting cluso and heater, and are telling me something that I already tried and found not true. If I could simply have the new cog take over the last state, then why does it not work when I have the new cog outa the last state the other cog was in, and try to move to the next outa state?
    I believe Cluso and Heater are right, it is being OR'd... I can confirm this later by taking the last cog1 state and do an OR calculation to see what the proper value for cog2 would be.
    The PE book teaches the opposite of what you are telling me about the stack. Please see page# 73 in the PE textbook... it teaches to address stacks sequentially from lowest to highest. so cognew(method, @stack[100])... cognew(method, @stack[200]) and so on. This is the way I have used it and it works great right now... so I am not going to change it.
  • Mike GreenMike Green Posts: 23,101
    edited 2011-10-20 16:26
    MagIO2 is not wrong. Cogs can share I/O pins as long as the Or'd nature of the I/O pins is respected. I have an I/O driver for the C3 board designed to share the SPI select circuitry pins, a /Clear and a Count pin. When any particular cog is finished with the SPI bus, it sets both the /Clear and the Count bits of its OUTA register to zeroes. Any other cog can set its /Clear bit to a one which allows the select counter to increment. The Count pin can be toggled twice to increment the select counter and leave it in a sharable state. The /Clear bit has to be set back to zero when the cog is done with the bus to clear the counter and to allow other cogs to increment it.
  • Heater.Heater. Posts: 21,230
    edited 2011-10-20 20:24
    No need to experiment. The ORing of outputs of COGs into the final pin state is in the manual with a nice diagram showing it.

    As for the stacks, it makes no difference what order you give stack blocks to COGs. Assumming the each block is big enough for the stack requirements of the COG it is given to.

    However it is true that Spin uses stack from low to high as it runs. This is opposite to most processor stacks. Mostly when using Spin you neither need to know or care about that. BUT there is some code around that relies on the ordering of parameters and variables on the stack, lonesocks floating point object for example. That really is somewhat advanced stuff though, not to mention using the language in undocumented ways.
  • MagIO2MagIO2 Posts: 2,243
    edited 2011-10-21 01:01
    Maybe the part you were missing is "set the OUTA of the inactive COG to 0". Make yourself confident with the truth table of the OR operation. If the inactive COG has PIN 0 set to high, the active COG can't change that! So for a takeover the inactive COG has to set all PINs to 0 that shall be useable by the active COG.

    Depending on the hardware you attached, it might be necessary to do the takeover in several steps:
    1. the COG that's going to be switched to inactive has to tell the other COG what the state is (via HUB-RAM/wrlong/rdlong or using a PIN as signal)
    2. the active COG reads it (INA) and set's the OUTA accordingly
    3. the active COG tells the inactive COG that it can "release" the outputs (again using HUB-RAM or a PIN)
    4. now the active COG has full control and can change PINs as desired

    Why? Because one output might be a clock signal. If the state before switch is 1 and the inactive COG releases the outputs before the active COG sets it to 1, there will be an unintended 1-0-1 transition on the clock line.

    Of course there is a lot of hardware which does not need such a takeover. Each COG simply starts fresh again.

    Again ... for the stacks ....
    Please read the PE textbook again! If you have a stack defined having 400 longs:
    long stack[400]

    the indexes allowed to use are in the range 0 - 399

    If you then start a COG with
    cognew( dosomething, @stack[400] )

    you definitely do something wrong! And depending on what the main cog is doing and what the new COG is doing, your program might fail sooner or later!

    Have a closer look at the PE lesson. I'm sure it starts the first new COG with
    cognew( do1, @stack[0] )
    then cognew( do2, @stack[100] )
    then cognew( do3, @stack[200] )
    and finally cognew( do4, @stack[300] )

    so that the 4th COG started can use stack[300] up to stack[399].

    Maybe worth to mention: The COG which runs your Main program does not need an explicit stack. It's implicitly using the whole remaining memory (not occupied by SPIN, VAR, DAT) as it's stack. In your short program this stack starts directly behind your stack variable. The last buggy cognew which used an illegal stack-index definitely destroyed the stack of your Main. Maybe you did not see any effects because the Main ends in an endless loop anyway but maybe parts of your initial problem was just because of that.
  • JBWolfJBWolf Posts: 405
    edited 2011-10-21 20:55
    Aha, thanks for clearing that up... its hard to get the proper perspective while learning, many times I am 'trapped' in a certain way of thinking and have a hard time breaking out of that box.

    Your right, I did miss the first cog being declared @stack[0].... but how does a @stack[300] know to use 300-399? is this because we are assuming the initial VAR stack is set at [400]? so if it was VAR'd at [1000] it would use 300-999?
    How can you 'release' outputs in a cog that is still active? Is there a way to let it know that it will no longer be using certain pins and basically null the dira[pins] for that cog? Meaning no OR's will happen as that cog is no longer using an outa.
    Or by releasing do you mean setting the outa in the cog to zeros, this way any outa's from a new cog will be OR'd and will still be the same value as the new outa.

    I am starting to think in terms of dedicating a cog to declaring the actual outa[pins] and using globals, this way I can write as many methods as I would like and they can all access the same pins through a global variable.
    Seems to me this will keep the OR comparisons to a minimum and very easy to manage.
  • Heater.Heater. Posts: 21,230
    edited 2011-10-21 23:29
    The Spin stack grows upwards not downwards as is normal for mosr CPUs. So if you pass a COG a new stack location as @stack[ 300 ] the stack will grow up wards from the 300 location as far as it needs.
    Better not to funnel all your I/O through one COG. There is no problem using DIRA, INA,OUTA from each COG as intended and as everyone else does. Pushing eveeything through one COG will be more complex and slow and may not play well with all the existing objects out there yo may want to use.

    In guess "releasing" the pins could be taken two ways.
    1) Have the COG set DIRA bit to zero for those pins so that any other COG can use then as input or output.
    2) Have the COG set the OUTA bits as zero so that any other COG can drive the output high as it likes, but cannot use as input in this case.
    It's up to you but I think the former option is better in general.
  • MagIO2MagIO2 Posts: 2,243
    edited 2011-10-22 04:09
    Maybe I should have said it in a different way.
    so that the 4th COG started can use stack[300] up to stack[399]
    actually means
    399 is the max. index available for the last COG. But there is no check! If you call to much subfunctions within other subfunctions or use to much locale variables/parameters, nothing will avoid overwriting parts of the memory which is behind the stack! These are the funny bugs because anything unpredictable can happen.

    A dedicated COG is ok if you can efford a COG not doing much more than that and if you can live with the drawback in speed. If your signals need a tight timing it might be difficult to meet that needs. And even there you have the question "How do you manage access to the variable?" As soon as more than 1 COG has to change bits in this variable you need to synchronize access to that variable.
  • JBWolfJBWolf Posts: 405
    edited 2011-10-23 01:06
    Oh no I dont mean use one cog for ALL I/O.
    I mean using one cog to control one logical group.... such as:
    motor one pins [8..11] = cog 1
    motor two pins [12..15] = cog2
    led pins [20..21] = cog 3 and so on
    This way they are all independent and easy to manipulate

    One thing I am not sure about...
    Lets say I do it this way and each cog has a global for 'enabling'...
    So making one motor move can simply be done like this: MotorX := 2 'causes the X axis motor to move 2 steps.
    And same with the other motor: MotorY := 3 ' causes the Y axis motor to move 3 steps

    So how can I make motor X and motor Y move at the same time?
    If I set one global at a time, then one will move before the other correct?
    So can I do something like:
    MotorX := 2 and MotorY := 3
    So that it will set both variables at the SAME time?
  • Heater.Heater. Posts: 21,230
    edited 2011-10-23 03:18
    Surely the time taken to set two variables is insignificant when dealing with motors.
    No you cannot set two variables at the same time.
    If the range of values of the two command variables is small enough to be represented in 16 bits then you can combine them both into a single LONG and write that in one go as the command for both motors.
  • MagIO2MagIO2 Posts: 2,243
    edited 2011-10-23 03:59
    Hmm ... not sure if it's not better to drive both motors with one COG in this case. Might also depend on what you want to do with the motors. When moving a significant mass the optimal driver would also include ramp up and ramp down functions. You'd have to spend a lot of code for synchronization if you have a relation between the 2 motors but they are driven by 2 independend COGs.

    With a single COG you can simply implement the bresnham algorithm for 2 "lines" and let one loop drive both motors.

    But even then the problem remains. How would this driver know when setting motorX and motorY is consistently done? A very common way in different drivers is that they have a command/parameter structure somewhere in HUB-RAM. In your case you'd need 1 variable for the command and 2 variables for the parameters. First the program that wants the motors to move would set both parameters. Then it sets the command variable to CMD_MOVE (for example =1) - this is a constant you'd define in the driver-object. When the driver is done with moving the motor it would set the command variable to CMD_READY = 0. This way the main program can also sync with the driver and wait until the driver is done before setting the next values.
Sign In or Register to comment.