Servo32v3 Variable Conflict?
dbpage
Posts: 217
Servo32v3 move some servos unexpectedly with when used with my code. My code is very complex so I created a simple demo of the problem (see Figure 1). I modified Servo32v3 to return pointers to variables used by Servo32v3 so the demo can output the pointers and contents to the PC (see Figure 2 for the output, and the attachment for the modified Servo32v3 code).
Figure 2 shows that one pointer, ZoneClocks, shares one of the ServoData array memory location. Some ServoData array memory locations are filled with unexpected data. ServoData memory locations 0 through 18 should be filled with "$1D4C0" except for servo 12, which should be "$13880." You'll also notice that PanServo 12 is at memory location ServoData[noparse][[/noparse]18]. What's up with this?
When I use Servo32v3 with my code, I find that variables in other procedures, which should be completely separate, share Servo32v3 memory locations, causing servos to move unexpectedly.
I can't figure out what is wrong. Is the bug in my demo, Servo32v3 or the compiler? Your feedback will be appreciated.
Figure 1:
Figure 2 Output:
Servo32v3 Conflict
Variable Pointer Data
ZoneClocks $000006DC $00000000
ServoData $000006D8 $00000000
ServoData 00 $000006D8 $00000000
ServoData 01 $000006D9 $00000000
ServoData 02 $000006DA $00000002
ServoData 03 $000006DB $00061A80
ServoData 04 $000006DC -$00030D41 <- ZoneClocks
ServoData 05 $000006DD $400FFFFF
ServoData 06 $000006DE $0001D4C0
ServoData 07 $000006DF $0001D4C0
ServoData 08 $000006E0 $0001D4C0
ServoData 09 $000006E1 $0001D4C0
ServoData 10 $000006E2 $0001D4C0
ServoData 11 $000006E3 $0001D4C0
ServoData 12 $000006E4 $0001D4C0
ServoData 13 $000006E5 $0001D4C0
ServoData 14 $000006E6 $0001D4C0
ServoData 15 $000006E7 $0001D4C0
ServoData 16 $000006E8 $0001D4C0
ServoData 17 $000006E9 $0001D4C0
ServoData 18 $000006EA $00013880 <- Servo 12
ServoData 19 $000006EB $0001D4C0
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Dennis B. Page, Page Radio Company
Post Edited (Dennis B. Page, Page Radio Company) : 5/12/2008 12:46:16 AM GMT
Figure 2 shows that one pointer, ZoneClocks, shares one of the ServoData array memory location. Some ServoData array memory locations are filled with unexpected data. ServoData memory locations 0 through 18 should be filled with "$1D4C0" except for servo 12, which should be "$13880." You'll also notice that PanServo 12 is at memory location ServoData[noparse][[/noparse]18]. What's up with this?
When I use Servo32v3 with my code, I find that variables in other procedures, which should be completely separate, share Servo32v3 memory locations, causing servos to move unexpectedly.
I can't figure out what is wrong. Is the bug in my demo, Servo32v3 or the compiler? Your feedback will be appreciated.
Figure 1:
{{ Servo32v3 Conflict Demo based on Servo32_v3 Demo v1.3 Written 11 May 2008 by Dennis B. Page - May connect a servo to PanServo pin (optional) - Open a terminal to see results ***************************************** * Servo32_v3 Demo v1.3 * * Author: Beau Schwabe * * Copyright (c) 2007 Parallax * * See end of file for terms of use. * ***************************************** }} CON _clkmode = xtal1 + pll8x 'Set for SS1 Spin Stamp 1 _xinfreq = 10_000_000 'Note Clock Speed for your setup!! PanServo = 12 'Select DEMO servo to pan VAR long ServoDataPtr long ZoneClocksPtr long I OBJ SERVO : "Servo32v3 Modified" 'Modified to return pointers debug : "Simple_Serial" num : "Numbers" PUB Main debug.start(31, 30, 9600) num.init debug.str(string(13,10,13,10,"Servo32v3 Conflict",13,10)) debug.str(string("Variable Pointer Data",13,10)) repeat I from 0 to 19 'preset ALL servos to center position SERVO.Set(I,1500) SERVO.Start(ServoDataPtr,ZoneClocksPtr) 'start servo handler debug.str(string("ZoneClocks ")) 'send pointers and contents to PC debug.str(num.ToStr(@ZoneClocksPtr,%11_000_000_0_0_001010_10000)) '8 hex digits zero padded debug.tx(" ") debug.str(num.ToStr(ZoneClocksPtr,%11_000_000_0_0_001010_10000)) '8 hex digits zero padded debug.tx(13) debug.tx(10) debug.str(string("ServoData ")) debug.str(num.ToStr(@ServoDataPtr,%11_000_000_0_0_001010_10000)) '8 hex digits zero padded debug.tx(" ") debug.str(num.ToStr(ServoDataPtr,%11_000_000_0_0_001010_10000)) '8 hex digits zero padded debug.tx(13) debug.tx(10) repeat I from 1000 to 2000 'sweep PanServo back and forth once waitcnt(cnt+40_000) 'control ramp rate SERVO.Set(PanServo,I) repeat I from 2000 to 1000 waitcnt(cnt+40_000) SERVO.Set(PanServo,I) repeat I from 0 to 19 'send pointers and contents to PC waitcnt(clkfreq/10000 + cnt) 'wait a few moments debug.str(string("Servo Data ")) debug.str(num.ToStr(I,%11_00000+%1010)) '2 decimal digits zero padded debug.str(num.ToStr(@ServoDataPtr+I,%11_000_000_0_0_001010_10000)) '8 hex digits zero padded debug.tx(" ") debug.str(num.ToStr(ServoDataPtr[i],%11_000_000_0_0_001010_10000)) '8 hex digits zero padded debug.tx(13) debug.tx(10) waitcnt(clkfreq/4 + cnt) 'allow time for PC to display everything before shutdown {{ ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ 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]
Figure 2 Output:
Servo32v3 Conflict
Variable Pointer Data
ZoneClocks $000006DC $00000000
ServoData $000006D8 $00000000
ServoData 00 $000006D8 $00000000
ServoData 01 $000006D9 $00000000
ServoData 02 $000006DA $00000002
ServoData 03 $000006DB $00061A80
ServoData 04 $000006DC -$00030D41 <- ZoneClocks
ServoData 05 $000006DD $400FFFFF
ServoData 06 $000006DE $0001D4C0
ServoData 07 $000006DF $0001D4C0
ServoData 08 $000006E0 $0001D4C0
ServoData 09 $000006E1 $0001D4C0
ServoData 10 $000006E2 $0001D4C0
ServoData 11 $000006E3 $0001D4C0
ServoData 12 $000006E4 $0001D4C0
ServoData 13 $000006E5 $0001D4C0
ServoData 14 $000006E6 $0001D4C0
ServoData 15 $000006E7 $0001D4C0
ServoData 16 $000006E8 $0001D4C0
ServoData 17 $000006E9 $0001D4C0
ServoData 18 $000006EA $00013880 <- Servo 12
ServoData 19 $000006EB $0001D4C0
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Dennis B. Page, Page Radio Company
Post Edited (Dennis B. Page, Page Radio Company) : 5/12/2008 12:46:16 AM GMT
Comments
The only code that stores into hub memory is the "set" routine in "Servo32v3".
The first parameter is the value to be converted for display, not the address of the value.
If you want to display the address of the servo datum, you need to call num.toStr(ServoDataPtr+4*i,...
If you want to display the actual value of the servo datum, you need to call num.toStr(long[noparse][[/noparse]ServoDataPtr+4*i],...
This assumes that "ServoDataPtr" is the address of the first long of the servo data array.
Where can you post a question on Mother's Day, take your mother out, and come back after dinner and have a reply waiting? The Parallax Forum!
1. It's amazing that no one else noticed that only 31 memory locations are defined by ServoData[noparse][[/noparse]31]. Servo32v3 has been in the object exchange for months!
2. You're correct. Servo32v3 only reads ServoData. An object other than SetServo (such as the demo) is changing values in the ServoData array unexpectedly, which is the problem I'm trying to solve.
3. I'm not getting good results. The addresses are zero and the values are unrecognizable. I tried num-toStr(ServoDataPtr+(4*i),... and num.toStr(long[noparse][[/noparse]ServoDataPtr+(4*i)],... to force the order of precedence. The addresses start at zero and the values are the code at the memory locations in reverse order. Since I don't know what I'm doing, I also tried num-toStr(ServoDataPtr[noparse][[/noparse]4*i],... and num.toStr(long[noparse][[/noparse]ServoDataPtr][noparse][[/noparse]4*i],.... Again, I get different results, but still unrecognizable. My random attempts to find the right syntax isn't working. Conceptually, I get it. In the demo object, ServoDataPtr contains an address that points to a long-aligned array defined by Servo32v3. The demo object doesn't know that ServoDataPtr is a long-aligned array, so the index is byte-aligned and needs to be multiplied by 4. I expect the address of all variables to be between $06DC and $07D7. I expect every variable to have different starting addresses. I expect 4 bytes for longs. I got good addresses with num.toStr(@ServoDataPtr,..., but I was getting the address to the variable that contained the pointer to ServoData, not the address of ServoData. At this point, I am becoming a typing monkey hoping to eventually write a masterpiece, or at least something sensible.
Independent of the above, if I declare the demo or Servo32_v3 variables in a different order, the objects become unstable and the servos go crazy. What else might I doing wrong?
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Dennis B. Page, Page Radio Company
2) Normally, routines outside of Servo32_v3 can't change (or even access) the variables declared inside Servo32_v3. Only the Set method can change them. That said, there's no checking in Spin
for array accesses out of bounds or invalid pointers.
3) Take out your changes to Servo32_v3. They won't work anyway. Take out the extra parameters. Since you're not using the return value, add the statement "result := @ZoneClocks" somewhere in the start method.
In your demo program, change your servo start statement to "myPointer := SERVO.start" where "myPointer" is declared as a long variable. From then on, you can access ZoneClocks as
"long[noparse][[/noparse]myPointer]", NoGlitch as "long[noparse][[/noparse]myPointer+4]", ServoPinDirection as "long[noparse][[/noparse]myPointer+8]" and ServoData[noparse][[/noparse] i ] as "long[noparse][[/noparse]myPointer+8+4*i]".
I hadn't looked at your changes to the start method. Parameters in Spin are strictly value parameters. They're copied into local variables during the call and any references
to the parameters are the local copies. If you assign values to them, you're changing the local copies only. Only the "result" gets copied back.
1) Thank you for pointing out that Servo32v3 assembly language index begins with ZoneClocks and increments by 4 for subsequent variables, thus making the order of the variables important.
2) I use the Set method to set values in ServoData. I am using the pointer to only read ServoData, which is available to other objects with proper indexing.
3) Thank you for teaching me Parameters 101. Parameters passed from one object to another are returned only if pointers are passed, or by using the return method.· Also thank you for Long 101 and showing me long[noparse][[/noparse]myPointer] syntax.
4) "long[noparse][[/noparse]myPointer+4]" and "long[noparse][[/noparse]myPointer+8+4*i]" do not work.· "long[noparse][[/noparse]myPointer][noparse][[/noparse]3+i]" works.· It appears that the compiler is aware that the variables are long-aligned.··I do·need to use "num.ToStr(myPointer+12+4*i..." for proper display of "i".
My output is as expected:
Servo32v3 Conflict 5/13/08
Variable········· Pointer··· Data
ZoneClocks······· $0000074C· $00061A80
NoGlitch········· $00000750 -$00030D41
ServoPinDirection $00000754· $400FFFFF
ServoData···· 00· $00000758· $0001D4C0
ServoData···· 01· $0000075C· $0001D510
ServoData···· 02· $00000760· $0001D560
ServoData···· 03· $00000764· $0001D5B0
ServoData···· 04· $00000768· $0001D600
ServoData···· 05· $0000076C· $0001D650
ServoData···· 06· $00000770· $0001D6A0
ServoData···· 07· $00000774· $0001D6F0
ServoData···· 08· $00000778· $0001D740
ServoData···· 09· $0000077C· $0001D790
ServoData···· 10· $00000780· $0001D7E0
ServoData···· 11· $00000784· $0001D830
ServoData···· 12· $00000788· $00013880
ServoData···· 13· $0000078C· $0001D8D0
ServoData···· 14· $00000790· $0001D920
ServoData···· 15· $00000794· $0001D970
ServoData···· 16· $00000798· $0001D9C0
ServoData···· 17· $0000079C· $0001DA10
ServoData···· 18· $000007A0· $0001DA60
ServoData···· 19· $000007A4· $0001DAB0
See the attachments for the revised code.· Thanks to your help, I now have a debugging tool to see what's clobbering the ServoData values. Stay tuned for the results ...
·
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Dennis B. Page, Page Radio Company
Post Edited (Dennis B. Page, Page Radio Company) : 5/14/2008 1:43:49 AM GMT