HSERVO Command...

Pertains to 8.0.1.3 and up.

The old ENABLEHSERVO command required arguments. In this scenario you input the pins used as 1’s and you can set up the low (1000), high (2000) values for min and max, and the 20 is the refresh rate.

enablehservo %0000000000001111,1000,2000,20

The new ENABLEHSERVO command does not require arguments. The pins used are automatically enabled. The range is +/- 12000 with 0 being centered. The resolution is 0.125uS or 8 clock pulses per uS.

The rest of the HSERVO commands work as before.

This forum post can help you make an SSC-32 emulation (Group Move).
lynxmotion.net/viewtopic.php?t=1242

The refresh rate can be changed using HSERVO_defines but I don’t have the format yet.

Edit: I added this additional information.

HSERVO system documentation.

Commands:
ENABLEHSERVO
no syntax. Must be included somewhere in program inorder to load the necessary interrupt handler.

HSERVO [pin\pos\speed]
pin = pin number to generate servo signal on
pos = position to move servo arm too. range ±12000. position is in clock cycles(1/16000000 of a second,.0625us), centered at 1500us
speed = how fast to move to new position. Must already be at a known position to use. First time using HSERVO should use a speed of 0. Speed of 0 means move to position immediately.

GETHSERVO pin,pos{,idle}
pin = pin number of servo signal to get current position from
pos = variable to store current postion in
idle = (optional) true/fals is servo idle

HSERVOWAIT [pin]
pin = pin number of servo signal to wait until servo has finished moving.

The HSERVO subsystem is driven using the TimerW(or TimerZ0 if using AtomPro40) timer hardware. This means users should not modify the TimerW TCNT or change any TimerW register values. However, values may be read. Also TimerW interrupts should not be accessed by user code.

The HSERVO interrupt handler is very efficient however it can still cause timing problems in software bitbanged commands(eg serin,serout,pulsin,pulsout etc…). The serin.out commands are most effected because of their more critical timing requirements.

The HSERVO subsystem has a compile time definition that may be used to adjust it’s refresh rate:
HSERVO_PERIOD
can be adjusted to change the refresh rate of servos. Default value is 64000(50000 for 3687). Setting a higher value will slow the refresh rate for the given number of servo groups. Setting a lower value will increase the refresh rate.
Formula to calculate the period based on the desired refresh rate:
(AtomPro)
16000000 / (5hz) = period
(AtomProPlus)
20000000 / (8
hz) = period

To set this value in your program add a line like this:
HSERVO_PERIOD con 50000

I’m going to be posting a new version of AtomPro IDE with an experimental version of HSERVO sometime tomorrow(our FTP server crashed last week and I haven’t gotten the new password yet, doh, or I’d post it today). I’d like some people to try it out and get back to me with problems/feedback.

The difference between this version and the old one is this one doesn’t reset the TimerW timer. Also this one includes a 64bit timer tick. I’ll post an example tomorrow as well. If this one works well I’ll be building a couple of new commands around the timer tick(which I’ll make available without HSERVO as well for those that don’t need HSERVO but want the timer tick)

These are the first couple commands I plan on adding:
GetTimerTick
HPause
HPauseus
HASerin
HPulsin

The plan for HASerin is to use a WKP or IRQ pin and the timertick. I’ve already got a flow chart of this and it appears it should work. In the end this should work just like HSerin with a little more overhead. “HA” stands for “Hardware Assisted”.

HPulsin will run in the background(again using a WKP or IRQ pin) and will use a data buffer much like HSerin(circular queue that keeps the last X pulses received).

Upto 10 HASerin and/or HPulsin will be able to run at once(eg 5 and 5,1 and 9,10 and 0 etc…). See the pinouts for the modules to see what pins have WKP/IRQ functions

Also I’m going to make the buffer sizes(on commands that have buffers) adjustable through the “EnableBlahBlah” commands(eg EnableHSerial insize,outsize).

I also have some vauge ideas for multitasking via the timertick. Nothing definite yet.

Anyone with comments or suggests please pass them on. Obviously this isn’t going to happen over night. I’m making these plans for the next 6 months or so.

The experimental version is now available.

www.basicmicro.com/downloads/software/B … 016Exp.exe

Have fun.

I’ll be updating the expiremental version to 2.0.1.7EXP this weekend.

The new expiremental version of AtomPro basic is available. Also here is a modified IRPD/Brat code that shows how to take advantage of the TimerW tick.

www.basicmicro.com/downloads/software/B … 017Exp.exe

This example code also shows how to use ONASMINTERRUPT

[code];USEASM con 0 ;uncomment to use ONASMINTERRUPT version of WKP handler

;System variables
righthip con p15
rightknee con p14
rightankle con p13
lefthip con p12
leftknee con p11
leftankle con p10

;calibrate steps per degree.
stepsperdegree fcon 166.6

;calibrate servos to “zero”.
;When properly homed in the servos are at 0 degrees
;the robot should be standing strait with
;irpd pointing up and AtomPro chip pointing forward.
righthip_start con -1000
rightknee_start con 0
rightankle_start con 0

lefthip_start con -1500
leftknee_start con -1500
leftankle_start con 0

;Interrupt init
ENABLEHSERVO

#ifndef USEASM
ONINTERRUPT WKPINT_3,handle_irpd
PMR5.bit3 = 1
ENABLE WKPINT_3
#else
ONASMINTERRUPT WKPINT,handle_irpd
PMR5.bit3 = 1
ENABLE WKPINT
#endif

command var byte

;End of System setup. Add user variables below this line.

;Init positions
;Note, movement subroutine arguments are Rightankle,Rightknee,Righthip,Leftankle,Leftknee,Lefthip,speed
gosub movement 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
low 1
low 2
pause 1000

lasttime var long
currenttime var long
diff var long
datacount var byte
irpd_data var word

command=0xFF
main
if(command<>0xFF)then
if(command = 1) then ;(Button 2) Walk Forwards
gosub movement -7.0, 20.0, 20.0, 7.0,-20.0,-20.0, 500.0]
gosub movement 7.0, 20.0, 20.0, -7.0,-20.0,-20.0, 500.0]
gosub movement 7.0,-20.0,-20.0, -7.0, 20.0, 20.0, 500.0]
gosub movement -7.0,-20.0,-20.0, 7.0, 20.0, 20.0, 500.0]
elseif(command = 4) ;(Button 5) Walk Backwards
gosub movement -7.0,-20.0,-20.0, 7.0, 20.0, 20.0, 500.0]
gosub movement 7.0,-20.0,-20.0, -7.0, 20.0, 20.0, 500.0]
gosub movement 7.0, 20.0, 20.0, -7.0,-20.0,-20.0, 500.0]
gosub movement -7.0, 20.0, 20.0, 7.0,-20.0,-20.0, 500.0]
elseif(command = 18) ;(Up Vol) long stride forward
gosub movement -12.0, 45.0, 45.0, 12.0,-45.0,-45.0, 750.0]
gosub movement 12.0, 45.0, 45.0,-12.0,-45.0,-45.0, 750.0]
gosub movement 12.0,-45.0,-45.0,-12.0, 45.0, 45.0, 750.0]
gosub movement -12.0,-45.0,-45.0, 12.0, 45.0, 45.0, 750.0]
elseif(command = 19) ;(Dn Vol) long stride backward
gosub movement -12.0,-45.0,-45.0, 12.0, 45.0, 45.0, 750.0]
gosub movement 12.0,-45.0,-45.0,-12.0, 45.0, 45.0, 750.0]
gosub movement 12.0, 45.0, 45.0,-12.0,-45.0,-45.0, 750.0]
gosub movement -12.0, 45.0, 45.0, 12.0,-45.0,-45.0, 750.0]
elseif(command = 2) ;(Button 3) Kick
gosub movement 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 500.0]
gosub movement 42.0, 0.0, 0.0,-14.0, 0.0, 0.0, 500.0]
gosub movement 0.0,-32.0, 41.0,-23.0, 0.0, 0.0, 500.0]
gosub movement 0.0, 24.0,-20.0,-23.0, 0.0, 0.0, 250.0]
gosub movement 0.0, 0.0, 0.0,-18.0, 0.0, 0.0, 500.0]
gosub movement 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 500.0]
sound 9,[50\3960]
pause 50
sound 9,[50\4400]
pause 50
sound 9,[50\3960]
elseif(command = 16) ;(Channel Up) Get up from front
gosub movement 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 500.0]
gosub movement 0.0, 90.0, 45.0, 0.0, 90.0, 45.0, 500.0]
gosub movement 40.0, 90.0,-37.0, 0.0, 90.0, 45.0, 500.0]
gosub movement 0.0, 90.0,-65.0, 0.0, 90.0,-65.0, 500.0]
pause 500
gosub movement 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 750.0]
sound 9,[50\4400]
pause 50
sound 9,[50\4400]
pause 50
sound 9,[50\3960]
elseif(command = 17) ;(Channel Dn) Get up from back
gosub movement 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,1000.0]
gosub movement 0.0,-90.0, 5.0, 0.0,-90.0, 5.0,1000.0]
gosub movement 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,1000.0]
pause 1000
gosub movement 0.0, 22.0,-80.0, 0.0, 22.0,-80.0,1000.0]
gosub movement 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,1000.0]
sound 9,[50\3960]
pause 50
sound 9,[50\3960]
pause 50
sound 9,[50\4400]

   elseif(command = 0)                                    ;(Button 1) Home Position 
     gosub movement   0.0,  0.0,  0.0,  0.0,  0.0,  0.0, 500.0] 
     sound 9,[50\4400] 
     pause 50 
     sound 9,[50\4400] 
     pause 50 
     sound 9,[50\4400] 
  elseif(command = 5)                                    ;(Button 6) Headbutt 
     gosub movement   0.0,  0.0,  0.0,  0.0,  0.0,  0.0, 500.0] 
     gosub movement   0.0,-50.0,-90.0,  0.0,-50.0,-90.0, 500.0] 
     gosub movement   0.0, 32.0,-58.0,  0.0, 32.0,-58.0, 400.0] 
     pause 200 
     ;gosub movement   0.0,-11.0,  7.0,  0.0,-11.0,  7.0, 500.0] 
     gosub movement   0.0,  0.0,  0.0,  0.0,  0.0,  0.0, 500.0] 
     sound 9,[50\4400] 
     pause 50 
     sound 9,[50\3960] 
     pause 50 
     sound 9,[50\3960] 
  elseif(command = 6)                                    ;(Button 7) Turn 
     gosub movement   0.0,-35.0,-40.0,  0.0, 35.0, 37.0,500.0] 
     gosub movement   0.0, 35.0, 37.0,  0.0,-35.0,-40.0,500.0] 
     gosub movement -14.0, 35.0, 37.0, 20.0,-35.0,-40.0,500.0] 
     gosub movement -14.0, 35.0, 37.0, 20.0, 35.0, 37.0,500.0] 
     gosub movement  20.0, 35.0, 37.0,-14.0, 35.0, 37.0,500.0] 
     gosub movement  20.0,-35.0,-40.0,-14.0, 35.0, 37.0,500.0] 

     ;gosub movement   0.0,-35.0,-70.0,  0.0, 35.0,  7.0,500.0] 
     ;gosub movement   0.0, 35.0,  7.0,  0.0,-35.0,-70.0,500.0] 
     ;gosub movement -14.0, 35.0,  7.0, 20.0,-35.0,-70.0,500.0] 
     ;gosub movement -14.0, 35.0,  7.0, 20.0, 35.0,  7.0,500.0] 
     ;gosub movement  20.0, 35.0,  7.0,-14.0, 35.0,  7.0,500.0] 
     ;gosub movement  20.0,-35.0,-70.0,-14.0, 35.0,  7.0,500.0] 

  elseif(command = 3)                                    ;(Button 4) Rest Position 
     gosub movement   0.0, 45.0, 45.0,  0.0, 45.0, 45.0, 500.0] 
  endif 
  Command=0xFF 

endif
goto main

;Should never need to edit anything below this line. Add user subroutines above this and below main.
lefthippos var float
leftkneepos var float
leftanklepos var float
righthippos var float
rightkneepos var float
rightanklepos var float
last_lefthippos var float
last_leftkneepos var float
last_leftanklepos var float
last_righthippos var float
last_rightkneepos var float
last_rightanklepos var float
lhspeed var float
lkspeed var float
laspeed var float
rhspeed var float
rkspeed var float
raspeed var float
speed var float
longestmove var float
;movement [lefthippos,leftkneepos,leftanklepos,righthippos,rightkneepos,rightanklepos,speed]
movement [rightanklepos,rightkneepos,righthippos,leftanklepos,leftkneepos,lefthippos,speed]
if(speed<>0.0)then
gosub getlongest[lefthippos-last_lefthippos, |
leftkneepos-last_leftkneepos, |
leftanklepos-last_leftanklepos, |
righthippos-last_righthippos, |
rightkneepos-last_rightkneepos, |
rightanklepos-last_rightanklepos],longestmove
speed = ((longestmovestepsperdegree)/(speed/20.0))
gosub getspeed[lefthippos,last_lefthippos,longestmove,speed],lhspeed
gosub getspeed[leftkneepos,last_leftkneepos,longestmove,speed],lkspeed
gosub getspeed[leftanklepos,last_leftanklepos,longestmove,speed],laspeed
gosub getspeed[righthippos,last_righthippos,longestmove,speed],rhspeed
gosub getspeed[rightkneepos,last_rightkneepos,longestmove,speed],rkspeed
gosub getspeed[rightanklepos,last_rightanklepos,longestmove,speed],raspeed
else
lhspeed=0.0;
lkspeed=0.0;
laspeed=0.0;
rhspeed=0.0;
rkspeed=0.0;
raspeed=0.0;
endif
hservo [lefthip\TOINT (-lefthippos
stepsperdegree) + lefthip_start\TOINT lhspeed, |
righthip\TOINT (righthipposstepsperdegree) + righthip_start\TOINT rhspeed, |
leftknee\TOINT (-leftkneepos
stepsperdegree) + leftknee_start\TOINT lkspeed, |
rightknee\TOINT (rightkneeposstepsperdegree) + rightknee_start\TOINT rkspeed, |
leftankle\TOINT (-leftanklepos
stepsperdegree) + leftankle_start\TOINT laspeed, |
rightankle\TOINT (rightanklepos*stepsperdegree) + rightankle_start\TOINT raspeed]
hservowait [lefthip,righthip,leftknee,rightknee,leftankle,rightankle]
last_lefthippos = lefthippos
last_leftkneepos = leftkneepos
last_leftanklepos = leftanklepos
last_righthippos = righthippos
last_rightkneepos = rightkneepos
last_rightanklepos = rightanklepos
return

one var float
two var float
three var float
four var float
five var float
six var float
getlongest[one,two,three,four,five,six]
if(one<0.0)then
one=-1.0one
endif
if(two<0.0)then
two=-1.0
two
endif
if(three<0.0)then
three=-1.0three
endif
if(four<0.0)then
four=-1.0
four
endif
if(five<0.0)then
five=-1.0five
endif
if(six<0.0)then
six=-1.0
six
endif
if(one<two)then
one=two
endif
if(one<three)then
one=three
endif
if(one<four)then
one=four
endif
if(one<five)then
one=five
endif
if(one<six)then
one=six
endif
return one

newpos var float
oldpos var float
longest var float
maxval var float
getspeed[newpos,oldpos,longest,maxval]
if(newpos>oldpos)then
return ((newpos-oldpos)/longest)*maxval
endif
return ((oldpos-newpos)/longest)*maxval

#ifndef USEASM
handle_irpd
enable

;Get current timer tick
mov.w	@_TIMERWTICK:16,e0
mov.w	@TCNT,r0
mov.l	er0,@CURRENTTIME:16

;increment data bit count
datacount=datacount+1
	
;calc pulse width
diff=currenttime-lasttime

;save current time so we can calculate the pulse width of the next pulse	
lasttime = currenttime

if(diff>44800 AND diff<49920)then	;If we get a start pulse reset datacount and irpd_data
	datacount=0
	irpd_data=0
elseif(diff>25600 and diff<30720)	;we got a "1" pulse
	irpd_data.bit10=1
elseif(diff>16640 and diff<21760)	;we got a "0" pulse
	irpd_data.bit10=0
else								;we got an invalid pulse so reset
	datacount=0
endif

if(datacount=11)then
	datacount=0
	command = irpd_data&0x7F
endif

;get ready for next data bit
irpd_data=irpd_data>>1

resume

#else
BEGINASMSUB
handle_irpd
;save workspace registers
push.l er0
push.l er1

;Clear WKP int flag
mov.b	@IWPR:8,r0l
and.b	#0xC0,r0l
mov.b	r0l,@IWPR:8

;re-enable ints to reduce possible glitching of HSERVO or other interrupts that may be enabled
andc		#0x7F,ccr

;Get current timer tick
mov.w	@_TIMERWTICK:16,e0
mov.w	@TCNT,r0
mov.l	er0,@CURRENTTIME:16

;increment data bit count
;datacount=datacount+1
mov.b	@DATACOUNT:16,r0l
inc.b	r0l
mov.b	r0l,@DATACOUNT:16
	
;calc pulse width
;diff=currenttime-lasttime
mov.l	@LASTTIME:16,er1
mov.l	@CURRENTTIME:16,er0

;save current time so we can calculate the pulse width of the next pulse	
;lasttime = currenttime
mov.l	er0,@LASTTIME:16

sub.l	er1,er0						;er0 holds diff

;if(diff>44800 AND diff<49920)then	;If we get a start pulse reset datacount and irpd_data
;	datacount=0
;	irpd_data=0
;elseif(diff>25600 and diff<30720)	;we got a "1" pulse
;	irpd_data.bit10=1
;elseif(diff>16640 and diff<21760)	;we got a "0" pulse
;	irpd_data.bit10=0
;else								;we got an invalid pulse so reset
;	datacount=0
;endif
cmp.l	#44800,er0
ble		NOT_START:8
cmp.l	#49920,er0
bge		NOT_START:8
xor.w	r0,r0
mov.b	r0l,@DATACOUNT:16
mov.w	r0,@IRPD_DATA:16
bra		FINISH_PULSE:8

NOT_START:
cmp.l #25600,er0
ble NOT_ONE:8
cmp.l #30720,er0
bge NOT_ONE:8
mov.w @IRPD_DATA:16,r0
bset #2,r0h
mov.w r0,@IRPD_DATA:16
bra FINISH_PULSE:8
NOT_ONE:
cmp.l #16640,er0
ble NOT_ZERO:8
cmp.l #21760,er0
bge NOT_ZERO:8
mov.w @IRPD_DATA:16,r0
bclr #2,r0h
mov.w r0,@IRPD_DATA:16
bra FINISH_PULSE:8
NOT_ZERO:
xor.b r0l,r0l
mov.b r0l,@DATACOUNT:16
FINISH_PULSE:

;if(datacount=11)then
;	datacount=0
;	command = irpd_data&0x7F
;endif
mov.b	@DATACOUNT:16,r0l
cmp.b	#11,r0l
bne		FINISH_DATA:8
xor.b	r0l,r0l
mov.b	r0l,@DATACOUNT:16
mov.w	@IRPD_DATA:16,r0
and.b	#0x7F,r0l
mov.b	r0l,@COMMAND:16

FINISH_DATA:

;get ready for next data bit
;irpd_data=irpd_data>>1
mov.w	@IRPD_DATA:16,r0
shlr.w	r0
mov.w	r0,@IRPD_DATA:16

;restore workspace registers
pop.l	er1
pop.l	er0

rte

ENDASMSUB
#endif[/code]

Looks good :slight_smile: , I will give it a shot!

Taking a quick look through the code, I was wondering/assuming:

  1. _TIMERWTICK is an external variable used in your HSERVO function and contains the overflow from the 16 bit counter. The combination of _TIMERWTICK and TCNT gives you a 32 bit unscalled processor timer tick (CKS0-2)=000 of TCRW

  2. This timer and the like is probably only valid if HSERVO is enabled

  3. My assumption is this release does not contain HASerin? It will be interesting to see if using this on your TV Brat if you can achieve reliable serial communication at 2400 or 9600 (or better) without having to disable the WKP Interrupt.

  4. I am glad you put in the ASM version of the IRPD handler. Looking at the ASM code, you make the assumption that it is WKP3. The question will be if you choose to implement HASerin and I assume HASerout, using one of the WKP interrupts, you may need to add some type of hand off mechanisim. Maybe something like: (Note: I have not verified if I have totally correct ASM here)

[code]BEGINASMSUB
handle_irpd
;save workspace registers
push.l er0
push.l er1

;Clear WKP int flag
mov.b @IWPR:8,r0l

btest #3:3,r01
beq OUR_WKP
pop.l er1 ; Not ours, restore registers go to default
pop.l ER0
bra _DefaultWKPHandler

OUR_WKP:
and.b #0xC0,r0l
mov.b r0l,@IWPR:8

;re-enable ints to reduce possible glitching of HSERVO or other interrupts that may be enabled
andc #0x7F,ccr

[/code]

As I said it is looking good! It is great to simply have a Timer Tick, without us having to produce another wone with TimerA.

Kurt

Yes, it is currently stored in some extra workspace memory allocated for HSERVO. The _TIMERWTICK is actually 48bits. Combined with the 16bits form TCNT you have a 64bit tick counter. I only used the low 32bits because I didn’t need any more for the IRPD/brat code.

I’ll be adding a standalone ENABLEHTIMERWTICK which will enable/allocate it by itself if you are not using HSERVO.

Correct, HASerial is a ways off. I’ll be using a system similar to that used by the IRPD routine in the Brat code. I expect to be able to handle atleast upto 115200bps pretty well. As long as the user WKPINT isn’t massive this shouldn’t be a problem. Also reenabling ints at the begining of user ints should mitigate this aquite a bit.

If a WKP happens that isn’t for a HASerial pin then I’ll forward to the defined WKPINT handler(eg that defined by the ONINTERRUPT or ONASMINTERRUPT commands or the default, do nothing, handler). A similar system is already inplace for Basic WKP ints(since they are all processed through one interrupt).

Don’t expect to see HASerin for awhile. My first new commands will be GetHTimerWTick, HPause and HPauseus.

I don’t plan on a HASerout at the moment. This may change in the future.

Thanks Nathan, this like fun to play with :smiley:

I will convert my brat and Rover WKP and IRQ intercepts over to using this timer. I will probably convert all of the WKP code to ASM as to try to reduce the overhead. (Handling Hservo, 6 WKPs and 2 other IRQs) is probably eating up a few resources of the BAP.

I am thinking about making the following modification to your asm version:

[code]BEGINASMSUB
handle_irpd
;save workspace registers
push.l er0
push.l er1

;Clear WKP int flag
mov.b @IWPR:8,r0l
and.b #0xC0,r0l
mov.b r0l,@IWPR:8

;re-enable ints to reduce possible glitching of HSERVO or other interrupts that may be enabled
andc #0x7F,ccr

;Get current timer tick
_ROLLEDOVER:
mov.w @_TIMERWTICK:16,e0
mov.w @TCNT,r0
cmp.w @_TIMERWTICK:16,e0
bne _ROLLEDOVER

[/code]
What do you think? Is this a little to Anal? Being a person who used to work on system code, I worry about edge conditions. In this case the 16 bit timer could have rolled over while the first mov.w was happening and we would have gone off to process the TimerW overflow interrupt handler or some other interrupt that just happened to occur between these two instructions. What do you think?

I think what you have is the only way to do it after you re-enable ints. If you want to get the count before re-enabling ints you do almost the same thing but you check if the OVF flag has been set and if so you increment your copy of _TIMERWTICK. eg:

mov.w @_TIMERWTICK:16,r0
btst #7,@TIERW:8
beq _DONTINC:8
inc.w #1,er0
_DONTINC:

So use yours if you’ve already re-enabled the int and use mine if you haven’t. This also shows that if you have an int that takes more than 65536 clock cycles and you don’t re-enable the int you can cause the tick to loose an overflow. That would be a pretty big int though. :slight_smile:

Assumptions on ONASMINTERRUPT for WKP.

I assume since you added the ONASMINTERRUPT using WKPINT, that you can also pass WKPINT to ENABLE and DISABLE. It compiles. SO I will begin to test the code now. (Note I am using the 8.0.1.7exp with the WTIMER code. I have coded up the assembly version of the code to measure the pulse widths of all 6 channels of the HITEC with the assumption that When channel 0 is complete channel 1 is high, then 2… From Oscilloscope output, it looked close enough for my purposes.

If anyone is interested I will post the code later. But first it is time to debug it. Also my Assembly language skills are a bit rusty so there are probably some optimizations that could be done to my code. Things like what are the best ways to address a member of an array of long integers…

Using 8.0.1.7EXP you can use WKPINT with “enable”. It is broken in the regular 8.0.1.7 though.

On my version of the BRAT(…1.7exp), if I compile the code, which is still using the basic version of the WKP handler, I receive a compiler error:

C:\PROGRA~1\BASICM~1\BASICA~2\bin\ld.exe : Unsupported .stab relocationc:\users\kurt\desktop\lynxmotion\bratwithremote.o(.text+0x26f): undefined reference to `WKPINT' C:\PROGRA~1\BASICM~1\BASICA~2\bin\ld.exe : Unsupported .stab relocation c:\users\kurt\desktop\lynxmotion\bratwithremote.o(.text+0x2c7): undefined reference to `WKPINT'

I am still investigating as your version appears to compile fine with or without assembly version.

Let me know if you find anything or post the code that causes the error so I can try it.

I sent you an email with the code. But I will also try to fix it by maybe using your assembly version…

Kurt

I’ll check it out first thing when I get in. I can’t access my work email from home. I also have a new EXP version. I went through and cleaned up a lot of code and changed some token handling. There are potentially a lot of bugs with this one, but in the long run this will improve performance significantly. Fastest command is still the “goto” but it has improved by about 66%(from 500k/sec or 32clocks to 888k/sec or 18clocks). Similar gains will be seen in other simple commands. Less gains in the more complex commands and of course no noticable gains in timing based commands. I’ll have the new one up sometime tomorrow.

Sounds great. I took my brat and cut away all of the older TimarA code (both versions - interrupt, non-interrupt) and converted over to using your version. It then compiled fine, but I was not getting any input from the TV remote until I remembered that I probably needed to explicitly tell the chip that the IO pin is now for interrupts and not a standard IO pin…

PMR5.bit3 = 1

Now it is working again! Sounds great that you are improving the speed of the commands. I will look forward to the new drop.

I am working on the handshaking for the brat to talk to the VB app on the PC again in a more reliable way… Making progress, but not quite there yet.

Also working on Rover intercepting 6 PWM signals (Hitec receiver) + 2 IRQS (encoders) and then try to output HSERVO commands to the motor controller. It is somewhat working, but the motors are really jerky right now. Guessing that the timings from PWMs are not consistent when the HSERVO is active, which makes the Encoder interrupt active… All Interrupt handlers are ASM (probably in need of performance enhancing)

Your are really pushing even what the AtomPro can do but I think it is all doable. Just going to take some tweaking. I’ll have the new EXP by tonight. Got delayed a little over the weekend.

I edited the original post to include additional Hservo information.

HSERVO system documentation.

Commands:
ENABLEHSERVO
no syntax. Must be included somewhere in program inorder to load the necessary interrupt handler.

HSERVO [pin\pos\speed]
pin = pin number to generate servo signal on
pos = position to move servo arm too. range ±24000. position is in clock cycles(1/16000000 of a second,.0625us), centered at 1500us
speed = how fast to move to new position. Must already be at a known position to use. First time using HSERVO should use a speed of 0. Speed of 0 means move to position immediately.

GETHSERVO pin,pos{,idle}
pin = pin number of servo signal to get current position from
pos = variable to store current postion in
idle = (optional) true/fals is servo idle

HSERVOWAIT [pin]
pin = pin number of servo signal to wait until servo has finished moving.

The HSERVO subsystem is driven using the TimerW(or TimerZ0 if using AtomPro40) timer hardware. This means users should not modify the TimerW TCNT or change any TimerW register values. However, values may be read. Also TimerW interrupts should not be accessed by user code.

The HSERVO interrupt handler is very efficient however it can still cause timing problems in software bitbanged commands(eg serin,serout,pulsin,pulsout etc…). The serin.out commands are most effected because of their more critical timing requirements.

The HSERVO subsystem has a compile time definition that may be used to adjust it’s refresh rate:
HSERVO_PERIOD
can be adjusted to change the refresh rate of servos. Default value is 64000(50000 for 3687). Setting a higher value will slow the refresh rate for the given number of servo groups. Setting a lower value will increase the refresh rate.
Formula to calculate the period based on the desired refresh rate:
(AtomPro)
16000000 / (5hz) = period
(AtomProPlus)
20000000 / (8
hz) = period

To set this value in your program add a line like this:
HSERVO_PERIOD con 50000

I have been reviewing some of the documention on the Atom Pro. I have found that some of the information that is both in the document that is currently downloaded with the IDE as well as the wiki is wrong. They both say that the POS has the range of ±12000. However the documention here as well as communicating with Nathan(AcidTech) says the range is 24000. Here is the what Nathan said:

At first this confused me, until I realized that this sescribed the whole range from 0 to 3ms. So to translate a desired uS value (X) into the pos value to pass to HSERVO can be calculated as: (X * 16) - 24000.

So if you took the information in the what is a servo you would have:

Degrees    us Pulse    Hservo Pos values]
-85            750             -12000
-45            900               -9600
0              1500                     0
45             2100               9600
85             2250              12000

As a side note, The TV brat code as well as the Rover Arm program uses a simple calculation that converts degrees into HSERVO values by multiplying by 166.6.

So ±45 degrees translates to ±7500
And ±90 translates to about ±1500

Which does not completly match but…

Also another note: Passing the value of -24000 generates a pulse width of 0, which turns an Analog servo off.

Does this make sense?

Any progress on this?

Is any of this in the current builds? In particular does HSERVO reset WTIMER in the current code or do you have it still keeping a 32 bit timer?

Do you still plan on exporting some Timer tick functions and values?

One reason I am asking this now is that once again in another piece of code we add a quick interrupt handler and the serial output to the LCD goes bad. So I am thinking of writing my own Serial Output function, that instead of counting clock cycles of instructions to delay for the pulse width, may instead try to watch the WTIMER value, which should hopefully shield it from going bad when a simple interrupt is processed.

Obviously I won’t be able to fully implement a serout command like:
TASerout pin, baudmode, …], as I don’t have the ability to add a new command, but maybe I will have a simple function with known parameters that can be passed in, with a buffer and size…

Thoughts?

Kurt

P.S. Sorry for bringing up a post from maybe 16 months ago.