SSC-32 Custom Firmware

[size=125]SSC-32 Firmware - DS Edition[/size]

Features:

  • Direct drive architecture
  • Ultra fast binary protocol
  • User selectable LED mode
  • Configurable input mode
  • Input support for analog, digital, latch low and latch hi
  • Batched input data
  • User selectable input resolution - 8 bit / 10 bit
  • 4 hardware 8ch/16ch mutltiplexer support
  • Servo offset support - full 8 bit range (-128 to 127)
  • Servo speed support
  • Timed servo command support
  • User selectable time unit - ms, cs, ds, sec
  • Reversible PWM outputs

Firmware:

Terminal:

Protocol: x16

Header:

  • Command: 6 bits - [00111111]
  • flag: 2 bits - [11000000]

//**************************************************
//* Command: CMD_GET_DEVICE_INFO
//* Desc: querry device informations
//**************************************************

Lenght: 2 byte
format: [header] [index]
command: [0x01] [0x00 - 0x05]

Index:
0x00 = firmware version (string)
0x01 = device name (string)
0x02 = device manufacturer (string)
0x03 = device ID - return 1 byte
0x04 = numeric version - return 2 byte [value].[value]
0x05 = external EEPROM - return 1 byte, 1 = eeprom found / 0 not found

*string = [num char] [data] …]

example: querrying the device for the firmware version

  • command: 0x01 0x00
  • return: 0x0C 0x53 0x53 0x43 0x33 0x32 0x2D 0x56 0x30 0x2E 0x33 0x44 0x53

//**************************************************
//* Command: CMD_GET_DEVICE_LED_STATE
//* Desc: querry the device LED state
//**************************************************

Lenght: 1 byte
format: [header]
command: [0x04]

return 1 byte - [led_State]

LED State:
0x00 = led_state_off
0x01 = led_state_on
0x02 = led_state_active_low
0x03 = led_state_active_hi

//**************************************************
//* Command: CMD_SET_DEVICE_LED_STATE
//* Desc: set the device LED state
//**************************************************

Lenght: 2 byte
format: [header] [led_state]
command: [0x05] [0x00 - 0x03]

LED State
0x00 = led_state_off
0x01 = led_state_on
0x02 = led_state_active_low
0x03 = led_state_active_hi

//**************************************************
//* Command: CMD_GET_SERIAL_TX_DELAY
//* Desc: querry the serial transmission delay
//**************************************************

Lenght: 1 byte
format: [header]
command: [0x0A]

return 2 byte [tx delay]

//**************************************************
//* Command: CMD_SET_SERIAL_TX_DELAY
//* Desc: set the serial transmission delay
//**************************************************

Lenght: 3 byte
format: [header] [tx_delay]
command: [0x0B] [0xFFFF]

minimum value: 10us
default value: 600us

//**************************************************
//* Command: CMD_GET_SERIAL_TX_PACING
//* Desc: set the serial transmission pacing
//**************************************************

Lenght: 1 byte
format: [header]
command: [0x0C]

return 2 byte [tx pacing]

//**************************************************
//* Command: CMD_SET_SERIAL_TX_PACING
//* Desc: set the serial transmission pacing
//**************************************************

Lenght: 3 byte
format: [header] [tx_delay]
command: [0x0D] [0xFFFF]

minimum value: 10us
default value: 70us

//**************************************************
//* Command: CMD_GET_DEVICE_TIME_UNIT
//* Desc: querry the current time unit
//**************************************************

Lenght: 1 byte
format: [header]
command: [0x08]

return 1 byte - [time unit]

time unit:
0x00 = ms
0x01 = cs
0x02 = ds
0x03 = sec

//**************************************************
//* Command: CMD_SET_DEVICE_TIME_UNIT
//* Desc: set the time unit
//**************************************************

Lenght: 2 byte
format: [header] [time unit]
command: [0x09] [0x00 - 0x03]

time unit:
0x00 = ms
0x01 = cs
0x02 = ds
0x03 = sec

//**************************************************
//* Command: CMD_GET_INPUT
//* Desc: querry the inputs mode and resolution
//**************************************************

Lenght: 1 byte
format: [header]
command: [0x1A]

return 5 byte - [resolution] [ModeA] [ModeB] [ModeC] [ModeD]

resolution: 0 = 8bit / 1 = 10bit

Mode*: 0x00 = Analog
0x01 = Digital
0x02 = Latch LOW
0x03 = Latch HI

//**************************************************
//* Command: CMD_SET_INPUT
//* Desc: set the inputs mode and resolution
//**************************************************

Lenght: 6 byte
format: [header] [resolution] [ModeA] [ModeB] [ModeC] [ModeD]
command: [0x1B] [0x00 - 0x01] [0x00] [0x01] [0x02] [0x03]

resolution: 0 = 8bit / 1 = 10bit

Mode*: 0x00 = Analog
0x01 = Digital
0x02 = Latch LOW
0x03 = Latch HI

//**************************************************
//* Command: CMD_GET_INPUT_DATA
//* Desc: querry the inputs
//**************************************************

Lenght: 1 byte
format: [header]
command: [0x1c]

8bit res: return 4 bytes - AxFF ] BxFF ] CxFF ] DxFF ]
10bit res: return 8 bytes - Ax03FF ] Bx03FF ] Cx03FF ] Dx03FF ]

  • 10bit resolution is sent over using 16bits data

//**************************************************
//* Command: CMD_GET_OUTPUT
//* Desc: querry PWM output state, normal/reverse
//**************************************************

Lenght: 2 byte
format: [header][index]
command: [0x10] [0x00 - 0x1F]

return 1 byte [state]

index: 0 - 31
state: 0 normal / 1 reverse

//**************************************************
//* Command: CMD_SET_OUTPUT
//* Desc: set PWM output state, normal/reverse
//**************************************************

Lenght: 3 byte
format: [header][index] [state]
command: [0x11] [0x00 - 0x1F] [0x00 - 0x01]

index: 0 - 31
state: 0 normal / 1 reverse

//**************************************************
//* Command: CMD_GET_OUTPUT_PWM
//* Desc: querry the output(s) current value
//**************************************************

Lenght: 5 byte
format: [header] [bank0] [bank1] [bank2] [bank3]
command: [0x12] [11111111] [11111111] [11111111] [11111111]

return 0 to 32 byte

example: querying the 32 outputs

  • command: 0x12 0xff 0xff 0xff 0xff

  • return: 0x96 0x96 0x96 0x96 0x96 0x96 0x96 0x96 0x96 0x96 0x96 0x96
    0x96 0x96 0x96 0x96 0x96 0x96 0x96 0x96 0x96 0x96 0x96 0x96 0x96 0x96
    0x96 0x96 0x96 0x96 0x96 0x96

//**************************************************
//* Command: CMD_SET_OUTPUT_PWM
//* Desc: set the output(s) PWM
//**************************************************

Lenght: 5-69 byte
format: [header] [bank0] [bank1] [bank2] [bank3] [output value] …]
command: [0x14] [11111111] [11111111] [11111111] [11111111] [0x0000 - 0xFFFF] …]

bank*: this is the banks information that hold the datas that specify the output index to move

output value:

  • off = 0
  • on = 65535
  • pwm = 1500-2500

example: set the output 0 to a PWM of 1500us

  • command: 0x15 0x01 0x00 0x00 0x00 0x05DC

example: move the 4 first outputs to 1500us

  • command: 0x15 0x0f 0x00 0x00 0x00 0x05DC 0x05DC 0x05DC 0x05DC

speed flag: [01000000]

if speed flag is on, the command expect to see 2 word data per output

format: [header] [bank0] [bank1] [bank2] [bank3] [output value] [speed] …] …]

example: move output 0 and 16 to 1000us with a speed value of 200

  • command: 0x4E 0x01 0x00 0x01 0x00 0x05DC 0x00C8 0x03E8 0x00C8

time flag: [10000000]

if time flag is on, time data must be inserted in front of the output pwm value(s)

format: [header] [bank0] [bank1] [bank2] [bank3] [time] [output value] …]

example: move output 0-1-16-17 to 2000us with a time value of 10000

  • command: 0x8E 0x03 0x00 0x03 0x00 0x03E8 0x2710 0x07D0 0x07D0 0x07D0

//**************************************************
//* Command: CMD_SET_OUTPUT_LOGIC
//* Desc: set output logic
//**************************************************


Lenght: 5-9 byte
format: [header] [bank0] [bank1] [bank2] [bank3] [bit value] …]
command: [0x15] [11111111] [11111111] [11111111] [11111111] [0xff] [0xff] [0xff] [0xff]

//**************************************************
//* Command: CMD_SET_OUTPUT_SPEED
//* Desc: change output speed while in motion
//**************************************************

Lenght: 4 byte
format: [header] [index] [speed]
command: [0x16] [0x00 - 0x1F] [0x07D0]

//**************************************************
//* Command: CMD_GET_OUTPUT_OFFSET
//* Desc: querry output PWM offset
//**************************************************

Lenght: 2 byte
format: [header] [index]
command: [0x17] [0x00 - 0x1F]

return 1 byte - [offset]

//**************************************************
//* Command: CMD_SET_OUTPUT_OFFSET
//* Desc: set output PWM offset
//**************************************************

Lenght: 3 byte
format: [header] [index] [offset]
command: [0x18] [0x00 - 0x1F] [0xff]

default value: 0
minimum value: -128
maximum value: 127

//**************************************************
//* Command: CMD_SET_OUTPUT_STOP
//* Desc: stop output(s)
//**************************************************

Lenght: 5 byte
format: [header] [bitbank0] [bitbank1] [bitbank2] [bitbank3]
command: [0x19] [11111111] [11111111] [11111111] [11111111]

example: stop all outputs

  • command: 0x19 0xff 0xff 0xff 0xff

//**************************************************
//* Command: CMD_GET_MULTIPLEXER
//* Desc: querry multiplexer configuration
//**************************************************

Lenght: 2 byte
format: [header] [index]
command: [0x20] [0x00 - 0x03]

return 7 byte - [type] [hardware processing] [pin_input] [pin_output0] [pin_output1] [pin_output2] [pin_output3]

index: 0-3

type: 0 = 8ch / 1 = 16ch
hardware processing: 0 = false / 1 = true
pin_intput: 0-3 (A B C D)
pin_output*: 0-31

//**************************************************
//* Command: CMD_SET_MULTIPLEXER
//* Desc: set multiplexer configuration
//**************************************************

Lenght: 9 byte
format: [header] [index] [type] [enable HP] [pin_input] [pin_output0] [pin_output1] [pin_output2] [pin_output3]
command: [0x21] [0x03] [0/1] [0/1] [0x04] [0x1F] [0x1F] [0x1F] [0x1F]

index: 0-3

type: 0 = 8ch / 1 = 16ch
hardware processing: true/false
pin_input: 0-3 (A B C D)
pin_output*: 0-31

//**************************************************
//* Command: CMD_GET_MULTIPLEXER_CHANNEL
//* Desc: querry the multiplexer’s current channel
//**************************************************

Lenght: 1 byte
format: [header]
command: [0x22]

return 1 byte - [ch index]

//**************************************************
//* Command: CMD_SET_MULTIPLEXER_CHANNEL
//* Desc: set the multiplexer channel
//**************************************************

Lenght: 2 byte
format: [header] [channel]
command: [0x23] [0x00 - 0x0f]

channel: 0-15

//**************************************************
//* Command: CMD_GET_MULTIPLEXER_DATA
//* Desc: querry the multiplexer datas
//**************************************************

Lenght: 2 byte
format: [header] [index]
command: [0x24] [0x03]

return 16 bytes - 0 to 15 channel datas

[code]#define CMD_GET_DEVICE_INFO 0x01

#define CMD_GET_DEVICE_LED_STATE 0x04
#define CMD_SET_DEVICE_LED_STATE 0x05

#define CMD_GET_DEVICE_PROTOCOL 0x06
#define CMD_SET_DEVICE_PROTOCOL 0x07

#define CMD_GET_DEVICE_TIME_UNIT 0x08
#define CMD_SET_DEVICE_TIME_UNIT 0x09

#define CMD_GET_SERIAL_TX_DELAY 0x0A
#define CMD_SET_SERIAL_TX_DELAY 0x0B

#define CMD_GET_SERIAL_TX_PACING 0x0C
#define CMD_SET_SERIAL_TX_PACING 0x0D

#define CMD_GET_OUTPUT 0x10
#define CMD_SET_OUTPUT 0x11
#define CMD_GET_OUTPUT_PWM 0x12
#define CMD_SET_OUTPUT_PWM 0x13
#define CMD_SET_OUTPUT_LOGIC 0x14
#define CMD_SET_OUTPUT_SPEED 0x15
#define CMD_GET_OUTPUT_OFFSET 0x16
#define CMD_SET_OUTPUT_OFFSET 0x17
#define CMD_SET_OUTPUT_STOP 0x18

#define CMD_SET_OUTPUT_BANK 0x19

#define CMD_GET_INPUT 0x1A
#define CMD_SET_INPUT 0x1B
#define CMD_GET_INPUT_DATA 0x1C

#define CMD_GET_MULTIPLEXER 0x20
#define CMD_SET_MULTIPLEXER 0x21
#define CMD_GET_MULTIPLEXER_CHANNEL 0x22
#define CMD_SET_MULTIPLEXER_CHANNEL 0x23
#define CMD_GET_MULTIPLEXER_DATA 0x24[/code]

hi guys

i currently work on a firmware for the ssc-32 that i will use in my projects.
though i could share the firmware in case someone would be interested.

in my first post on this forum, i said something about not having enough input for the sensors,
and Zoomkat kindly suguested to use a multiplexer to get more inputs(thanks man!). at first that did look great, but the more i though about it, the more problem i could see at the horizon…
it would be already slow to querry the ABCD inputs, couldnt imagine trying to update the 16 channels while trying to retreive the datas and pushing 60 fps for the servos… lets alone doing this for 4 multiplexer :confused:

on the official firmware to querry the 4 inputs, you need to send 9 bytes: VAVBVCVD to get 4 bytes in return…
this is not what i would call efficient nor fast.

hence the need to for a new protocol and mutliplexer hardware support!

but in the first place it was for the “servo move” command that i did want to write a new protocol.

here some numbers to compare LM protocols vs DS protocol using fixed scenario of 60 fps

[protocol - LM ASCII]

servo move

min 6 bytes - #0p500
max 8 bytes - #32p2500

18 servo = min 108 / max 144 / ~ 126
32 servo = min 192 / max 256 / ~ 224

18 servo: 60 fps * 126 = 7560 byte/sec
32 servo: 60 fps * 224 = 13440 byte/sec

[protocol - LM bin]

protocol : 80 03 E8 / B-W / opcode - data

1 servo: 3 byte
18 servo: 54 byte
32 servo: 96 byte

18 servo: 60 fps * 54 = 3240 byte/sec
32 servo: 60 fps * 96 = 5760 byte/sec

[protocol - DS x16]

servo move

protocol: B-BBBB-w*

1 servo: 7 byte
18 servo : 41 byte
32 servo: 69 byte

18 servo: 60 fps * 41 = 2460 byte/sec
32 servo: 60 fps * 69 = 4140 byte/sec

baud to byte table to compare the ssc-32 transfer speed with the protocols

115200 baud/sec = 14400 byte/sec
38400 baud/sec = 4800 byte/sec
9600 baud/sec = 1200 byte/sec
2400 baud/sec = 300 byte/sec

also all the commands/datas are processed upon arrival unlike LM’s firmware that use some kind of delayed work
i figured i could do everything w/o delaying any work as it didnt make sens to waste cpu time to build cmds to delay the work and finaly do the work later on anyway
but its been really hard to figure the way to process everything without delaying the work and most importantly w/o messing the timing.

in short it means, by the time LM firmware build the cmd workspace for later execution
my firmware is done processing the command/datas

ive also built a quick terminal to work on the firmware… its really basic and ugly but thats only to test stuff so

sending “cmd_get_device_info” return the firmware version just like VER in the original rom

here a screen shot after retriving the inputs state and the multiplexer config

with the mutliplexer’s enable HP(enable hardware processing) checked, the ssc-32 switch the channel in sync with the pulse width generation and gather the data in a buffer.

the multiplexers sampling rate is about 3 time per sec…

1000ms / 20 ms = 50 pulsewidth update/sec

50 / 16 ch = 3.125

so if using all 4 mux, this give 64 new value every ~ 0.33 sec

to accomplish that on the official firmware
we would need to send 3072 bytes/sec just to set the channels

  • 384 bytes /sec to querry the inputs

here a pic of my ssc32 and the multiplexer

as we can see the 3 first channels are connected and the first channel is a pot

now if we get the data here is what we get in the terminal

well i didnt push the tests very far yet… but pretty much everything seem to work well for what as been implemented exept for the set_multiplexer_channel function that seem to mess up the firmware a little but still work.
this release would probaly not be usable in a project, but its getting close to be usable

also ive been on this project for about 2 weeks and ive flashed the atmega chip hundred of time using LM terminal as this is the only way(that i know) to flash an .abl file.
but its getting old as sometime it take more time to flash the chip than it took to change the code…
if i could have the information on how to flash the abl file i would make a stand alone firmware updater that could work via command line… this would save me so much time!
maybe someone like Mike or the author of the LM terminal, or anyone else that as infos about that could give me some help on the procedure?
this would be really appreciated.

anyways…

ill post new release/update as the development goes

if you try this firmware please be carefull as i may not have tested all posible situation which could result in unexpected behavior… so be really carefull

Interesting. Could be used in a data logging setup.Also there have been attempts at terrain adaption that require input monitoring beyond the normal four inputs on an ssc-32.

this is exactly why i made that firmware… but it was not only to add hardware multiplexer support, but to speed up everything…

protocol is smaller which make communication goes faster
the code is also totaly different… and use much more less instructions than LM’s firmware… which allow to process more inputs per cycle(theoricaly)

datas are batched to reduce calls and internal processing…

so everything together that make things run much more lighter, faster and smoother

Which Multiplexer do you use?
CD74HC4067?

Greetings
Daniel

yes this the one that i use, made by sparkfun

This is interesting. Do the Ascii commands still work, or did you yank them out for more room?

the original code that process the commands is still there, but not called
some variables as been removed to fit the 4 multiplexer datas

the alpha release as only 4 bytes left of memory

Hi guys,

beta version is out

here a screen shot of the terminal

extended device info are now supported, but this is mainly to use in my standard module system that i will work on later…
doubt anyone will need these infos, and yet not fully implemented

header commands been rearranged as the command numbers was all over the place in the alpha release
commands should be more stable now and for the futur release

header as been split to 6:2 bits

first 6 bits is the header command
2 last bits are the command option flag/index

speed and time support as been added to the set_servo_pulsewidth command
and there are also a stand alone command to set the speed
this allow to change the speed of a servo in the middle of a move
probaly not usefull… but the command is there.

a big clean up been made in the code

the beta release is much more smaller than the alpha release
and more free memory as well

alpha release

AVR Memory Usage

Device: atmega168p

Program: 11978 bytes (73.1% Full)
(.text + .data + .bootloader)

Data: 1020 bytes (99.6% Full)
(.data + .bss + .noinit)

EEPROM: 512 bytes (100.0% Full)
(.eeprom)

beta release

AVR Memory Usage

Device: atmega168p

Program: 7052 bytes (43.0% Full)
(.text + .data + .bootloader)

Data: 981 bytes (95.8% Full)
(.data + .bss + .noinit)

EEPROM: 512 bytes (100.0% Full)
(.eeprom)

added serial tx delay and pacing commands as the variables are still used.
however ive not seen any change with the different values 10, 100, 1000 etc
so im not sure if it does actualy work

this version work very well so far. infact work good enough that i will flash the ssc-32 in my hex with that firmware and begin to use it

looks like ive srewed up the beta release :S well… the terminal atleast

though things did work well. but prior to update the ssc32 in my hex i performed couple more tests and things went totaly wrong…

when i tried to use the channel 8 to 31… the result were pretty instable… sometime it did work and sometime it did throw the servo off its limits
turn out it was just a code missing in the terminal which as been removed for debug purpose and forgot to put it back :confused:

but anyways… decided that i would fix some stuff on the firmware and just made a new release

nothing new in this release… just fixs and code change

added an all 1500 button just like in the official terminal… to help tests and debug
ive also took the binary compression out of the get_input/set_input command to keep the x16 protocol more user friendly

for more infos on the firmware release check the release.txt

Is there a lower servo u sec limit in the firmware? I’m just thinking if the servo control pulse width could be sufficiently reduced that the servo would not detect it as a signal and stop trying to hold position. This might be nice for continous rotation servos that have drifting neutral points and start to creep in one direction or the other.

eh, hum… thanks for the sticky :slight_smile:

actualy no, the pwm signals is caped to 500-2500. but i had planned to remove these limits eventualy, not for continous rotation though.

but i though continous rotation servo did stop to move at ~1500us? if so how it would help the neutral point to have lower and highter pwm limits?

The origional pots if retained tend to drift with vibration, temperature and maybe other factors. Pots replaced with resistors may also be affected by temperature. Tweeking the pots is delicate and a hassel to do. Continous rotation servos start to creep in one direction or the other when the pot value drifts. There is usually only a ~±5us deadband for no movement. The ssc-32 servo control pin can be set low, but that just adds complexity to the programming. There may be other situations where it is desired to have the servo “relax” and not try to hold a position. I haven’t tested to see if there is a lower us value where the servo considers a signal is not present.

edit:
It might be worth considering programming in certain high/low values (or character) that when present will turn the control pin on/off.

Why is setting a different value or character better than sending a L or H, which is already there, to do the same thing. In my experience analog servos do not ignore out of spec pulses. They pull slowly and weakly in one direction. The deadband is actually 220uS on the 1425 CR.

You’re welcome!

Nice work on the firmware and accompanying terminal. Very impressive!

Thank you Robo Dude.

i think Zoomkat mean adding a command in my firmware to set the output pins hi or low as this is not posible since the pulsewidth function is capped to 500-2500

setting a pin low/hi using the “L” and “H” method cost 3 or 4 bytes per pins + cr

#0H#31L

thats a 8 bytes command for 2 pins

should be able to set all the 32 pins with 6 to 9 bytes
not sure how i will implement that command yet…

I’ll have to experiment with the L, as it might do the job adequately well without modification. I think your 220us dead band is actually is the range for full rotation speed in one direction to full rotation speed in the other direction. In the servos I’ve modified for continous rotation that range is ~1400us to ~1600us when the neutral stopped position is 1500us. The servos will actually start to creep when the position is ~1495us or less and ~1505us or greater around the 1500us neutral point. You can see if this is applicable to the 1425 CR by using the up/down keys in lynxterm.

important suggestion Make the - character interchangable with the # character so that servo commands can be easily sent in an URL query_string GET request like below. The # character cannot be used in the GET query_string. This would allow persons to control the ssc-32 via a simple web page when using the apache web server and a simple cgi batch file.

something to think about expanding on the above, may develop a clever way to allow a number of ssc-32s to be operated on a single serial line. Some type of hardware setup to differentiate the boards would be required.

zoomkat.no-ip.com:88/cgi-bin/ech … P2250T2000

But zoomy, that would imply that I don’t fully understand the concept here, and clearly I do. I took two 425 CR servos off the shelf and well you know… tested them. Sigh… Hitec made this change long ago to prevent the creepy CR servo issue.

HSR-1425CR R/C servos?

I saw something like 8uS deadband 400uS ± control band.

I attempted to scale slow, half, fast and full into that control band range, but wasn’t totally successful. On top of that table, I wanted to add offsets to correct the speeds (L vs R), but that hasn’t been entirely successful either. If “Control Band” CR speeds (with corrections) could be built into the SSC32, that would be great!

Still trying to read wheel rotation speed. I’m experimenting with a Tach Jr. now.

Alan KM6VV