Shop Learn
cogspin questions — Parallax Forums

cogspin questions

Hi,
I am confused by what is happening in cogspin. I want to start a new cog that includes JonnyMac's JM_multi_adc.spin2 that starts out as " not a top object" when I start the new cog, call it looper, were all I want to do is to read 8 pins of analog and report it out in a global VAR, the compiler goes to the cogspin routine and then to never, never land. I guess I need more explanation about how to use COGSPIN.
Jim

Comments

  • pik33pik33 Posts: 1,138
    edited 2021-11-18 15:26

    Cogspin calls a Spin method in its own cog. This needs a cog, a method and several bytes of stack.

    Example from my program:

    First, declare the stack in your main program VAR section:

    long sbusstack[64]

    Second, write a method to work in its own cog, which in most cases has to be an infinite loop. In this case it receives and decodes SBUS bus placing results in "channel" which is also global variable array.
    Notice it calls another methods, this will be also done in the method's cog

    pub sbus()
    
    repeat
      waitms(20)
      if (receive_sbus(SBUS_RX, @frame))                          ' get s.bus frame
        pintoggle(56)
        decode_sbus(@frame, @channel)                             ' convert to channel values
    
    

    Now you can call cogspin

    cogspin(6,sbus(),@sbusstack)

    and the cog #6 will be executing sbus() method while your main cog will go to the next instructions.

    Use 16 as a cog number if you want to get a first free available cog.

  • JonnyMacJonnyMac Posts: 7,823
    edited 2021-11-18 16:56

    Keep in mind that Spin cogs have access to global objects and variables in your main application. For example, I'm working on a project that starts two copies of my jm_fullduplexserial and then launches a Spin cog that monitors one of those serial objects for commands coming from a serial HMI.

    I allow the Propeller to manage cog allocation with this syntax (NEWCOG lets the P2 select an available cog).

      ndcog := cogspin(NEWCOG, nextion_display(), @ndstack) + 1     ' load Nextion state processor 
    

    Another habit is to declare the method that will be run by the background cog as PRIvate -- this just reminds me not to call that like a normal method because that method will usually have an infinite repeat loop.

    pri nextion_display() | len
    
      repeat
        len := get_msg(@rxbuf, ND_BUFSIZE)
        if (len > 4)
          get_command()
          get_value()
          check_newpage()
    
          if (newpage)
            term.fstr1(string("Page %d\r"), page)
            if (cmdvalue == 0)
              load_page()
            newpage := false
    
          else
            process_page()
            clear_command()
    
  • RS_JimRS_Jim Posts: 1,525
    edited 2021-11-21 13:11

    ok, it is still not happening for me.
    I want to run the following code in a separate cog:
    '''

    {
    --------------------------------------------
    Filename: TX_robot_1.3.spin2
    Author Jim Meek with nrf24l01+ routines developed by:
    Author: Jesse Burt modded by Jim Meek
    Description: nRF24L01+ Transmit that uses the radio's
    auto-acknowledge function (Enhanced ShockBurst - (TM) Nordic Semi)
    tx-ad version to transmit results from adc smart pins
    Copyright(c) 2021
    Copyright (c) 2020
    Started Nov 23, 2019
    Updated Jan 25, 2020
    See end of file for terms of use.
    Note adc test removes most of the nrf code for the purposes of getting adc_multi object up and running
    when adc is running copyright notices will be properly noted and updated.
    --------------------------------------------
    this code has been moded for use with KISS0000_eval and KISS0001_eval
    which uses a 25MH xtal. Clock freq has also been upped to 200MHz from
    origional 160_000_000
    }

    CON

    _clkfreq        = cfg#_clkfreq_def
    _xtlfreq        = cfg#_xtlfreq
    

    ' -- User-modifiable constants
    LED = cfg.LED
    ' SER_BAUD = 2_000_000

    ''Group_Base_pin ==G_BP this allows a device to be positioned on any 8 pin boundry using P0-P7 and adding the G_BP
    g_bp0 = 0
    g_bp1 = 8
    g_bp2 = 16
    g_bp3 = 24
    g_bp4 = 32
    g_bp5 = 40
    g_bp6 = 48
    'g_bp7 = 56
    nrf_gbp = g_bp1 'group base pin for NRF24L01

    'NRF pins added to group base pin to determin io boundry
    IRQ = 0 '
    MISO = 1 ' AKA MISO 'form
    MOSI = 2 ' AKA MOSI
    SCK = 3 '
    CS = 4 '
    CE = 5 '
    SCK_Pin = SCK + nrf_gbp
    IRQ_PIN = IRQ + nrf_gbp
    MISO_PIN = MISO + nrf_gbp
    MOSI_PIN = MOSI + nrf_gbp
    CS_PIN = CS + nrf_gbp
    CE_PIN = CE + nrf_gbp
    SCK_FREQ = 5_000_000 ' 10_000_000 max
    CHANNEL = 113 ' 0..125

    adc_gbp = g_bp4                             'group base pin for adc
    adc_pin_count = 8                           'pin count for ADC pins
    admax = $FFF
    admid = $7FF
    lo    = 0
    hi    = 3.3
    
    SER_RX          = cfg#SER_RX
    SER_TX          = cfg#SER_TX
    SER_BAUD        = 115_200
    

    ' --

    CR = $0A
    LF = $0D
    CLEAR           = 1
    CHANNEL         = 113
    PC              = 2
    MAX_CH = 32                                                   ' 32 is absolute maximum
    

    OBJ
    ser : "com.serial.terminal.ansi"
    cfg : "core.con.boardcfg.P2_KISS000_eval"
    io : "io"
    time : "time"
    int : "string.integer"
    nrf24 : "wireless.transceiver.nrf24l01.spi"
    ' adc : "jm_adc_multi"
    VAR
    long loopCount ' to keep track of how many times the uarts have been restarted '
    long errors
    long _nrf24_cog,_ser_cog,adcCog,_adccog,loopercog
    long Serial
    long _pktlen
    long lstack[50]
    long adstack[50]
    long ap0 ' analog input channel 0 pin
    long nch ' number of channels
    long apg ' analog pins group
    long urlo[32] ' scaled user range, low
    long urhi[32] ' scaled user range, high
    long callo[32] ' calibration, ground
    long calhi[32] ' calibration, vio

    byte myBuf[34]
    byte _fifo[34]
    byte  cidx, didx, index
    

    ' byte IRQ_PIN, MISO_PIN, MOSI_PIN, SCK_PIN, CS_PIN, CE_PIN

    PUB main |choice, char,char1, flag, idx

    bytefill(@myBuf,0,33)
    Setup
    Serial(true) 'to go to standalone(no terminal) set serial to false

    pause(100)
    idx := 0
    _pktlen := 8
    repeat
    ser.position(0,5)
    'P2 fast enough to do adc reads inline rather than looping cog as in P1
    repeat idx from 0 to adc_Pin_Count
    ser.Str(String(CR,LF,"idx = "))
    ser.dec(idx)
    ser.Str(String(" mybuf = "))
    ser.dec(myBuf[idx])

    PUB Setup | okay
    repeat until _ser_cog := ser.StartRXTX (SER_RX, SER_TX, 0, SER_BAUD)
    ser.str(string("SCK =" ))
    ser.dec(SCK_PIN)
    ser.str(string(" IRQ ="))
    ser.dec(IRQ_PIN)
    ser.str(string(" MISO ="))
    ser.dec(MISO_PIN)
    ser.str(string(" MOSI ="))
    ser.dec(MOSI_PIN)
    ser.str(string(" CS ="))
    ser.dec(CS_PIN)
    ser.str(string(" CE ="))
    ser.dec(CE_PIN)
    ser.str(string(" adc base pin= "))
    ser.dec(adc_gbp)
    ser.str(string($0A,$0D))

    looperCog := CogSpin(NEWCOG, looper(adc_gbp,adc_pin_count,lo,hi),@adstack) + 1
    ser.str(string(CR,LF,"looper sucessfully started, looper cog number "))
    ser.dec(looperCog)
    {
    else
    ser.str(string(CR,LF))
    ser.str(string("adc cog failed to start"))
    FlashLED1(LED,250)

    }
    PUB looper(adc_gbp,adc_pin_count,lo,hi) |bSwap, bs1,bs2,bs3,bs4,idx,aidx,bidx

    start(adc_gbp,adc_pin_count,lo,hi)
    
    repeat
      aidx:=0
    
      repeat idx from 0 to 7
        aidx:=(adc_gbp + idx)    
        bswap:= read(aidx)         
        myBuf[idx]:=bswap
    

    pub start(base, count, lo, hi) : result | last

    '' Setup pin for analog input on count pins
    '' -- base is first pin of group
    '' -- count is number of (contiguous) analog input pins
    '' -- lo and hi define user range for the ADC inputs
    '' * scaled from ground to Vio (3.3v)
    '' * lo corresponds to 0.0v input, hi corresponds to 3.3v input

    if ((base < 0) || (base > 63)) ' validate base pin
    return false

    if ((count < 1) || (count > MAX_CH)) ' validate channel count
    return false

    last := base + count - 1 ' last ch pin of group

    if ((base < 32) && (last > 31))
    return false ' outa boundary error
    elseif (base < 64) && (last > 63)
    return false ' outb boundary error

    ap0, nch := base, count ' save 1st channel and count

    apg := ap0 addpins (nch-1) ' create group

    longfill(@urlo, lo, count) ' set initial range
    longfill(@urhi, hi, count)

    calibrate() ' calibrate analog input pin

    return true

    pub calibrate() | ch

    '' Calibrate analog input pin for 0 to 3.3v input
    '' -- 12 bits, using SINC2, 2048 samples

    pinstart(apg, P_ADC | P_ADC_GIO, 12-1, 0) ' measure ground
    waitct(getct() + (2048 << 2)) ' allow pin to stablize
    repeat ch from 0 to nch-1
    callo[ch] := rdpin(ap0+ch) ' save ground calibration level

    pinstart(apg, P_ADC | P_ADC_VIO, 12-1, 0) ' measure vio (3.3v)
    waitct(getct() + (2048 << 2))
    repeat ch from 0 to nch-1
    calhi[ch] := rdpin(ap0+ch) ' save 3.3v calibration level

    pinstart(apg, P_ADC | P_ADC_1X, 12-1, 0) ' set to pins, 1x scale
    waitct(getct() + (2048 << 2))

    pub set_range(ch, lo, hi)

    '' Reset user range for specific channel
    '' -- lo corresponds to 0.0v input
    '' -- hi corresponds to 3.3v input

    if ((ch >= 0) && (ch < nch))
    urlo[ch] := lo
    urhi[ch] := hi

    pub read(ch) : result | clo, chi, ulo, uhi

    '' Read channel pin and scale to user range
    '' -- simple mx+b

    if ((ch >= 0) && (ch < nch))
    clo, chi := callo[ch], calhi[ch] ' get channel calibration
    ulo, uhi := urlo[ch], urhi[ch] ' get channel user range
    result := (raw(ch)-clo) * (uhi-ulo) / (chi-clo) ' mx
    result := ulo #> result + ulo <# uhi ' +b (constrain to user range)

    pub raw(ch) : result

    '' Read raw analog level from channel pin
    '' -- not scaled to user range

    return ((ch >= 0) && (ch < nch)) ? rdpin(ap0+ch) : 0

    PUB FlashLED1(led_pin, delay_ms)

    io.Output(led_pin)
    repeat
        io.Toggle (led_pin)
        time.MSleep (delay_ms)
    

    '

    PUB HM
    ser.position(0,0)

    PRI pause(ms)

    DAT
    RFaddr BYTE $E7, $E7, $E7, $E7, $E7 'address used for transmitter&receiver id
    hello BYTE "Hello world, this is a tx test!" '31 + 1 zero byte string - only used by the Beacon method

    {
    --------------------------------------------------------------------------------------------------------
    TERMS OF USE: MIT License

    Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
    associated documentation files (the "Software"), to deal in the Software without restriction, including
    without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the
    following conditions:
    
    The above copyright notice and this permission notice shall be included in all copies or substantial
    portions of the Software.
    
    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
    LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
    IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
    SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    --------------------------------------------------------------------------------------------------------
    

    }

    '''
    I cannot figure out where the wheels have come off the track. When I start the main program (adctest) I have an on screen display of several i.o pins and that works fine but once it calls cogspin, it goes to never never land..
    Jim
    EDIT: I woke up at 3AM this morning remembering how to post code in the forum so I have re inserted the code, maybe it will make more sense.
    EDIT2: I changed the begining of looper code to this:
    '''
    PUB looper(adc_gbp,adc_pin_count,lo,hi)

    PUB begin()
    start(adc_gbp,adc_pin_count,lo,hi)

    repeat
      aidx:=0
    
      repeat idx from 0 to 7
        aidx:=(adc_gbp + idx)    
        bswap:= read(aidx)         
        myBuf[idx]:=bswap
    

    '''

  • pik33pik33 Posts: 1,138
    edited 2021-11-21 08:46

    I cannot see any cogspin in this code (and please edit the post so the code will be more readable)

    What you have to start in the cogspin is your main (don't forget about () - main() )

    cogspin(cog#,main(),stackspace)

    and you have to provide stackspace - 64 longs seems to be a safe valua for the start. Too low stack space causes the program to not work as expected.

  • AribaAriba Posts: 2,552

    The question is: Why do you want to start this in a new cog? The AD conversion is anyway made by the smartpins in background continuously. The only gain would be that the scaling calculation of the raw value is made by another cog, this saves a few microseconds when you read the value. But is it worth to waste a second cog for that.

  • RS_JimRS_Jim Posts: 1,525

    I edited post 3 to correct the code posting and to change the beginning of the looper cog to include a
    PUB begin().
    that solved the going off to never never land, but I am still not reading the ADC pins and reporting them to myBuf. I am just reading all 0. So if I can get @Jonny Mac to look at the code I will appreciate him showing me the error of my ways. I am using a stack size of 50 longs, I think that will be enough but will change to 64 to see if that helps.
    Jim

  • RS_JimRS_Jim Posts: 1,525

    @Ariba said:
    The question is: Why do you want to start this in a new cog? The AD conversion is anyway made by the smartpins in background continuously. The only gain would be that the scaling calculation of the raw value is made by another cog, this saves a few microseconds when you read the value. But is it worth to waste a second cog for that.

    No, I had started with an inline read and when it wasn't working,I thought perhaps it needed ti be run in it's own cog. I started it inline online.
    I am still not getting my analog resulta so I have yo go back anda review the adc code.
    Jim

  • pik33pik33 Posts: 1,138
    edited 2021-11-22 21:03

    Here is my simple object doing A/D conversion in a dedicated cog. I wrote this for measuring a battery voltage in a robot. Maybe in the future I will get rid of it and free this cog, but now it works as it is. The battery voltage is divided by 10 via a resistor divider and then it goes to the P2 pin, so this 33000 multiplier gives a milivolt result.

    {{ ADC example}}
    
    
    var
    long aresult
    long adcpin
    long agnd
    long avcc
    
    
    
    pub start(apin)     |iii, m, n
    
    adcpin:=apin
    coginit(16,@mixer,@aresult)
    waitms(100)
    
    pub measure() :voltage  
    
    
    return 33000*(aresult-agnd)/(avcc-agnd)
    
    
    
    DAT
                  org
    mixer         setq #3
                  rdlong aaresult,ptra
    
    
                  wrpin adc_config1, aapin
                  wxpin  #%00_1101, aapin
                  dirh   aapin
                  mov    x, #%001<<6
                  add    x,aapin
                  setse1 x
    
    loop          waitse1
                  rdpin x,aapin
                  waitse1
                  rdpin x,aapin   
                  waitse1
                  rdpin gnd,aapin 
    
                  wrpin adc_config2, aapin
    
                  waitse1
                  rdpin x,aapin
                  waitse1
                  rdpin x,aapin   
                  waitse1
                  rdpin vcc,aapin  
    
                  wrpin adc_config3, aapin
    
                  waitse1
                  rdpin x,aapin
                  waitse1
                  rdpin x,aapin   
                  waitse1
                  rdpin aaresult,aapin  
    
                  wrpin adc_config1, aapin 
                  setq #3
                  wrlong aaresult,ptra
    
                  jmp     #loop          'loop
    
    
    adc_config1      long    %0000_0000_000_100000_0000000_00_11000_0 ' 100000 gnd
    adc_config2      long    %0000_0000_000_100001_0000000_00_11000_0 ' 100001 3v3
    adc_config3      long    %0000_0000_000_100011_0000000_00_11000_0 ' 100011 pin
    
    x                long    0
    
    aaresult long 0
    aapin long 0
    gnd long 0
    vcc long 0
    
  • AribaAriba Posts: 2,552

    @RS_Jim said:

    @Ariba said:
    The question is: Why do you want to start this in a new cog? The AD conversion is anyway made by the smartpins in background continuously. The only gain would be that the scaling calculation of the raw value is made by another cog, this saves a few microseconds when you read the value. But is it worth to waste a second cog for that.

    No, I had started with an inline read and when it wasn't working,I thought perhaps it needed ti be run in it's own cog. I started it inline online.
    I am still not getting my analog resulta so I have yo go back anda review the adc code.
    Jim

    I think this is the problem:

    lo    = 0
    hi    = 3.3
    

    The read() scaling expects an integer value for hi. For float values you would need to modify the scaling code to use the new float operators.

    BTW. For a code block you need 3 backticks before and after the code, not these apostrophes.

  • RS_JimRS_Jim Posts: 1,525

    Hi,
    Well, programing can certainlymake you feel dumb sometimes!. I could not figure out why I could not get Jon's adc code to work. My problem was I was trying to feed the channel number with the pin number! Once setup is run, you feed the read instruction with the channel you want read and the program selects the correct pin based upon the setup information! What I was doing wrong finally hit me like a falling wall of bricks. Thanks to Ariba's comment I went back to my origonal plan to use inline c ode to read the adc..working fine now that i try to read the channel number not the pin number.
    Jim

Sign In or Register to comment.