This is an old revision of the document!
Parts that include the SigmaDSP processor can be loaded with arbitrary code that is generated by SigmaStudio. A firmware driver has been written to help simplify the process of parsing and loading this binary firmwares.
You should only need to invoke one function in order to load a binary blob:
extern int process_sigma_firmware(struct i2c_client *client, const char *name);
You pass the I2C client of the connected SigmaDSP and the name of the firmware blob to load (which normally corresponds to the modetype
attribute of the page
element).
The XML format allows multiple page
elements (with each including their own set of action
elements), but the firmware blob format splits each page
element into its own binary file. Otherwise, a lot of needless seeking/indexing would be required in the firmware format itself in order to support this. Filesystems are already pretty good at this kind of thing, and most people will only need a small number of firmware blobs in the first place.
Every firmware blob has a header which includes a magic string, version format identifier, and crc: <source trunk/include/linux/sigma.h:sigma_firmware_header{} c linux-kernel>
Then there are an arbitrary number of actions (which correspond to the action
xml element).
<source trunk/include/linux/sigma.h:sigma_action{} c linux-kernel>
The instr
field can be a few different things. Currently pllwait/noop are ignored, and the end action is redundant (end of file means end of page
data).
<source trunk/include/linux/sigma.h:/SIGMA_ACTION_/-/}/ c linux-kernel>
The len
and len_hi
fields can be combined to get the length of the payload
for the action. Whether this value needs to be subtracted by 2 is not yet decided (the original action
xml element declares the length as number of payload bytes + number of bytes for i2c register address).
<source trunk/include/linux/sigma.h:sigma_action_len() c linux-kernel>
The addr
field is the 16bit I2C register to write the payload
to in the device.
Each action must be padded to 16bits so that the structure can easily be read directly from the file without having to worry about unaligned issues. That means if the payload is not a multiple of 16bits, then it will have a pad byte appended to it automatically. There is a helper function for this: <source trunk/include/linux/sigma.h:sigma_action_size() c linux-kernel>
While the typical output of SigmaStudio is an XML file, processing this on the board would force a lot of ugly overhead. Until it supports exporting directly to a firmware blob, this shell script can be used to convert things.
#!/bin/bash set -e err() { echo "$*" 1>&2; } unset end export \ INSTR_writexbytes=0 \ INSTR_writesingle=1 \ INSTR_writesafeload=2 \ INSTR_delay=3 \ INSTR_pllwait=4 \ INSTR_noop=5 \ INSTR_end=6 awk 'BEGIN { printf "ADISIGM%c", 1; printf "%c%c%c%c", 0, 0, 0, 0; }' xml sel -t -c ROM/page/action "$1" | \ perl -p -e 's:\n::g' | \ sed \ -e 's:/>:\n:g' \ -e 's:</action>:\n:g' \ -e 's:<action ::g' \ -e 's:ParamName="[^"]*"::g' \ -e 's:CellName="[^"]*"::g' | \ sed -e 's: *>\(.*\): data="\1":' | \ tr '[:upper:]' '[:lower:]' | \ while read line ; do if [ "${end}" = "true" ] ; then err "error: too much input; page is supposed to be over" exit 1 fi unset instr len addr data eval $line export instr len addr data data=$(set -- ${data}; echo ${@/#/0x}) rlen=${len:-0} case $instr in writexbytes);; writesingle) len=3;; writesafeload);; delay) len=$(printf '%i' $data); unset data; rlen=0;; pllwait|noop) err "ignoring unsupported instruction: $instr"; continue;; end) end=true; continue;; esac instr="INSTR_${instr}" err "LINE: $line {inst:${!instr} rlen:${rlen}}" #struct sigma_action { # uint8_t instr; # uint8_t len_hi; # uint16_t len; # uint16_t addr; # unsigned char payload[]; #}; # awk 'BEGIN{printf "%i", '${!instr}';}' php -B " printf('%c', ${!instr}); /* instr */ printf('%c', 0); /* len_hi */ printf('%c', $((len % 256))); /* len (msb) */ printf('%c', $((len / 256))); /* len (lsb) */ printf('%c', $((addr % 256))); /* addr (msb) */ printf('%c', $((addr / 256))); /* addr (lsb) */ \$a = explode(' ', '${data}'); if (!(count(\$a) == 1 && \$a[0] == '')) { foreach (\$a as \$d) { printf('%c', 0+\$d); } if (count(\$a) % 2 == 1) printf('%c', 0); } " </dev/null || exit done