cogspin questions
in Propeller 2
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
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.
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()
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
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.
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.
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
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
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
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.
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