There's no doubt the VSA has become the defacto standard for servo control with props and many customers have asked us to "get compatible" with VSA. Honestly, we didn't know how so we downloaded the demo and found it's really not too tough.
The program below can be run by VSA and will give you eight servo outputs on P0 to P7 and eight digital (relay) outputs on P8 to P15. Once you've downloaded the program you connect your PC to the DB-9 connector on the Prop-SX.
You'll want to configure your VSA project like this:
Channels: 0 to 15
Channels 0 to 7:
* MiniSSC Servo
* +Value = 245
* -Value = 55
* Default = 150
Channels 8 to 15:
* MiniSSC Relay
* +Value = 254
* -Value = 0
* Default = 0
Set your COM port to 38400.
[Edit]: Posted updated version 16 JUN 2009
' =========================================================================
'
' File...... Servo8_Digital8.SXB
' Purpose...
' Author.... Jon Williams, EFX-TEK
' Copyright (c) 2008-2009 EFX-TEK
' Some Rights Reserved
' -- see http://creativecommons.org/licenses/by/3.0/
' E-mail.... jwilliams@efx-tek.com
' Started...
' Updated... 16 JUN 2009
'
' =========================================================================
' -------------------------------------------------------------------------
' Program Description
' -------------------------------------------------------------------------
'
' Servo controller/output device designed for use with VSA or other
' real-time serial control programs.
'
' P0 to P7.... Servo control
' P8 to P15... Digitial outputs
'
' The protocol is identical to the SEETRON (www.seetron.com) MiniSSC:
'
' <sync><channel><value>
'
' sync...... $FF (255)
'
' channel... 0 to 7 for servos
' 8 to 15 for digital outputs
'
' value..... 55 to 245 for servos (150 = center)
' >127 = on for digital channels
' <128 = off for digital channels
'
' Default baud rate is 38.4K but can be changed down to as low as 2400.
' -------------------------------------------------------------------------
' Conditional Compilation Symbols
' -------------------------------------------------------------------------
' -------------------------------------------------------------------------
' Device Settings
' -------------------------------------------------------------------------
ID "Servo8+8"
DEVICE SX28, OSCHS2, TURBO, STACKX, OPTIONX, BOR42
FREQ 50_000_000
' -------------------------------------------------------------------------
' I/O Pins
' -------------------------------------------------------------------------
Outs PIN RC OUTPUT ' solenoid control outputs
Out7 PIN RC.7 ' use P15/OUT15
Out6 PIN RC.6 ' use P14/OUT14
Out5 PIN RC.5 ' use P13/OUT13
Out4 PIN RC.4 ' use P12/OUT12
Out3 PIN RC.3 ' use P11/OUT11
Out2 PIN RC.2 ' use P10/OUT10
Out1 PIN RC.1 ' use P9/OUT9
Out0 PIN RC.0 ' use P8
ServoCtrl PIN RB OUTPUT ' servo control pins
Servo7 PIN RB.7 ' use P7
Servo6 PIN RB.6 ' use P6
Servo5 PIN RB.5 ' use P5
Servo4 PIN RB.4 ' use P4
Servo3 PIN RB.3 ' use P3
Servo2 PIN RB.2 ' use P2
Servo1 PIN RB.1 ' use P1
Servo0 PIN RB.0 ' use P0
TX PIN RA.3 OUTPUT ' to PC
RX PIN RA.2 INPUT ' from PC
SCL PIN RA.1 INPUT ' EE clock line (I2C)
SDA PIN RA.0 INPUT ' EE data line (I2C)
' Note: TX, SCL, and SDA lines are not used by this program
' -------------------------------------------------------------------------
' Constants
' -------------------------------------------------------------------------
IsOn CON 1
IsOff CON 0
Yes CON 1
No CON 0
LO_LIMIT CON 55 ' to prevent servo burn-up
HI_LIMIT CON 245
' Bit dividers for 3.255 uS interrupt
' -- ISR actually runs at 3.333 uS for better servo timing
Baud2400 CON 128
Baud4800 CON 64
Baud9600 CON 32
Baud19K2 CON 16
Baud38K4 CON 8
Baud1x0 CON Baud38K4 ' 1 bit period (ISR counts)
Baud1x5 CON Baud1x0 * 3 / 2 ' 1.5 bit periods
' -------------------------------------------------------------------------
' Variables
' -------------------------------------------------------------------------
flags VAR Byte ' (keep global)
isrFlag VAR flags.0
rxReady VAR flags.1 ' rx byte waiting
sync VAR Byte
chan VAR Byte
value VAR Byte
mask VAR Byte
rxSerial VAR Byte (16)
rxBuf VAR rxSerial(0) ' 8-byte buffer
rxCount VAR rxSerial( 8 ) ' rx bit count
rxDivide VAR rxSerial(9) ' bit divisor timer
rxByte VAR rxSerial(10) ' recevied byte
rxHead VAR rxSerial(11) ' buffer head (write to)
rxTail VAR rxSerial(12) ' buffer tail (read from)
rxBufCnt VAR rxSerial(13) ' # bytes in buffer
svoData VAR Byte (16) ' bank servo data
pos VAR svoData(0) ' position table
pos0 VAR svoData(0)
pos1 VAR svoData(1)
pos2 VAR svoData(2)
pos3 VAR svoData(3)
pos4 VAR svoData(4)
pos5 VAR svoData(5)
pos6 VAR svoData(6)
pos7 VAR svoData(7)
svoTix VAR svoData( 8 ) ' isr divider
svoFrame_LSB VAR svoData(9) ' frame timer
svoFrame_MSB VAR svoData(10)
svoIdx VAR SvoData(11) ' active servo pointer
svoTimer VAR svoData(12) ' pulse timer
svoPin VAR svoData(13) ' active servo pin
' =========================================================================
INTERRUPT NOPRESERVE 300_000 ' (4) run every 3.333 uS
' =========================================================================
Mark_ISR:
\ SETB isrFlag ' (1)
' -------
' RX UART
' -------
'
' UART code by C. Gracey, A. Williams, et al
' -- buffer and flow control mods by Jon Williams
'
Receive:
ASM
MOV FSR, #rxSerial ' (2)
JB rxBufCnt.3, RX_Done ' (2/4) skip if buffer is full
MOVB C, RX ' (4) sample serial input
TEST rxCount ' (1) receiving now?
JNZ RX_Bit ' (2/4) yes, get next bit
MOV W, #9 ' (1) no, prep for next byte
SC ' (1/2)
MOV rxCount, W ' (1) if start, load bit count
MOV rxDivide, #Baud1x5 ' (2) prep for 1.5 bit periods
RX_Bit:
DJNZ rxDivide, RX_Done ' (2/4) complete bit cycle?
MOV rxDivide, #Baud1x0 ' (2) yes, reload bit timer
DEC rxCount ' (1) update bit count
SZ ' (1/2)
RR rxByte ' (1) position for next bit
SZ ' (1/2)
JMP RX_Done ' (3)
RX_Buffer:
MOV W, #rxBuf ' (1) point to buffer head
ADD W, rxHead ' (1)
MOV FSR, W ' (1)
MOV IND, rxByte ' (2) move rxByte to head
INC rxHead ' (1) update head
CLRB rxHead.3 ' (1) keep 0..7
INC rxBufCnt ' (1) update buffer count
SETB rxReady ' (1) set ready flag
RX_Done:
ENDASM
' ----------------
' Servo Processing
' ----------------
'
Test_Servo_Tix:
ASM
BANK svoData ' (1)
INC svoTix ' (1) update divider
CJB svoTix, #3, Servo_Done ' (4/6) done?
CLR svoTix ' (1) yes, reset for next
' Code below this point runs every 10 uS
Check_Frame_Timer:
CJNE svoFrame_LSB, #2000 & 255, Inc_FrTmr ' (4/6) svoFrame = 2000 (20 ms)?
CJNE svoFrame_MSB, #2000 >> 8, Inc_FrTmr ' (4/6)
CLR svoFrame_LSB ' (1) yes, reset
CLR svoFrame_MSB ' (1)
MOV svoPin, #%00000001 ' (2) start servo sequence
CLR svoIdx ' (1) point to servo 0
MOV FSR, #pos ' (2)
MOV svoTimer, IND ' (2)
JMP Refesh_Servo_Outs ' (3)
Inc_FrTmr:
INC svoFrame_LSB ' (1) DEC svoFrame
ADDB svoFrame_MSB, Z ' (2)
Check_Servo_Timer:
TEST svoPin ' (1) any servos on?
SNZ ' (1)
JMP Servo_Done ' (1) no, exit
DEC svoTimer ' (1) yes, update timer
SZ ' (1) still running?
JMP Servo_Done ' (1) yes, exit
Reload_Servo_Timer:
INC svoIdx ' (1) point to next servo
CLRB svoidx.3 ' (1) keep 0 - 7
MOV W, #pos ' (1) get pulse timing
ADD W, svoIdx ' (1)
MOV FSR, W ' (1)
MOV W, IND ' (1)
MOV svoTimer, W ' (1) move to timer
Select_Next_Servo:
CLC ' (1)
RL svoPin ' (1)
Refesh_Servo_Outs:
MOV ServoCtrl, svoPin ' (2) update outputs
Servo_Done:
ENDASM
ISR_Exit:
RETURNINT ' (4)
' -------------------------------------------------------------------------
' Subroutine / Function Declarations
' -------------------------------------------------------------------------
RX_BYTE FUNC 1, 0 ' receive a byte
' =========================================================================
PROGRAM Start
' =========================================================================
Start:
TX = 1 ' set TX line to idle
' center servos
PUT pos, 150, 150, 150, 150, 150, 150, 150, 150
Main:
sync = RX_BYTE
IF sync <> $FF THEN Main
Get_Channel:
chan = RX_BYTE
IF chan = $FF THEN Get_Channel ' correct for re-sync
IF chan > 15 THEN Main ' check channel range
Get_Value:
value = RX_BYTE
IF value = $FF THEN Get_Channel ' correct for re-sync
Process_Value:
IF chan < 8 THEN ' servo channel?
value = value MIN LO_LIMIT ' force to legal limits
value = value MAX HI_LIMIT
pos(chan) = value
ELSE
chan.3 = 0 ' align for control port
mask = 1 << chan ' make channel bit mask
IF value.7 = 1 THEN ' >127?
Outs = Outs | mask ' yes, activate output
ELSE
Outs = Outs &~ mask ' no, deactivate output
ENDIF
ENDIF
GOTO Main
' -------------------------------------------------------------------------
' Subroutine / Function Code
' -------------------------------------------------------------------------
' Use: aByte = RX_BYTE
' -- returns "aByte" from 8-byte circular buffer
' -- will wait if buffer is presently empty
' -- rxBufCnt holds byte count of receive buffer (0 to 8)
FUNC RX_BYTE
ASM
JNB rxReady, @$ ' wait if empty
MOV FSR, #rxSerial ' point to serial vars
MOV W, #rxBuf
ADD W, rxTail ' point to rxBuf(rxTail
MOV FSR, W
MOV __PARAM1, IND ' get byte at tail
INC rxTail ' update tail
CLRB rxTail.3 ' keep 0..7
DEC rxBufCnt ' update buffer count
SNZ ' exit if not zero
CLRB rxReady ' else clear ready flag
MOV FSR, #__DEFAULT
ENDASM
ENDFUNC
' =========================================================================
' User Data
' =========================================================================
Jon,
I just ordered a prop-sx starter kit (it should be delivered by the time I get home today), and I plan on controlling 8 servos using VSA. I have a question about the connections. From what I understand, which is very little at this point, is that the servos will be connected to P0 - P7. Will I be able to power the servos using an external power source? The power supply I will be using has two outputs +12V @3A and + 5V @ 5A. The +12V will be used to power the Prop-SX. You have on on-board regualtor (I'm assuming +5V?) that supplies power to the on-board logic. I need to use external +5V to power the servos. Can this be done since the P0 output is based on the on-board regualtor?
You'll have to build an adapter to use external power; just make sure that your external supply is no more than 6v (double-check this with the servo vendor) and that you connect the ground side of your external supply to ground on the Prop-SX (GND terminal or any of the Px.B connections).
You can build a little power adapter from this schematic:
(http://www.efx-tek.com/files/ext_servo_power2.png)
... using our Proto PCB (http://www.efx-tek.com/topics/proto_pcb.html). The terminal block and male pin headers you can get from Mouser Electronics -- here are the part numbers I use:
* Terminal block: 571-2828362
* Male header: 517-6111TG
-- this is a 40-pin header; you can cut this down to strips of 8 -- use 3 to make a 3x8 header for servos
Jon,
Not to be picky, but I just noticed that the code listed in the first post is the Pulse Width modulation code, not the digital output code. The attached file is correct. I downloaded the code to start to figure out how it worked and noticed this problem. To avoid confusion, you should probably fix that.
Sorry about that -- goes to show that I'm human (despite rumors to the contrary).
I have posted the correct program, and it has been freshened a bit (the attached file was replaced, too).