OneTechnologyWay•P. O . Box9106•Norwood,MA02062-9106,U.S.A.•Tel : 781.329.4700•Fax :781.461.3113•www.analog.com
2
A Method for Compressing I
C Scripts for the
ADV74xx/ADV78xx V75xx/ADV76xx/AD
by Witold Kaczurba
INTRODUCTION
This application note describes a method for compressing larg
2
sets of I
ation herein is targeted for applications where the user needs to
put over 50 scripts to the memory of one single microcon
This method provides excellent results for sets of scripts
containing m
an I C bus.
Analog Devices, Inc., multiformat decoders allow users
decode various standards of video. Because a variety of
standards are supported, these video decoders provide various
settings. Each setting contains the bulk of I
mode. These writes are collected as scripts.
In some cases, the user may use hundreds of scripts to conf
many I
C scripts for microcontroller platforms. The inform-
ore than 200 scripts for more than six devices on
2
2
C
writes for each
2
C devices. In such a case, the user requires a lot of
TEXT FILE:
2
SET OF I
C SCRIPTS
troller.
to
igure
COMPRESSING
Figure 1. Concept of Compressing Algorithms
e
OCTAVE
SCRIPT
memory in a small microcontroller to keep all of these scripts.
Note that these scripts may have similar writes as well as unique
writes. This application note details how to compress the script
on the PC side, as well as how to write an efficient decompress
sing method on the microcontroller side. The decompressing
algorithm utilizes more efficient functions requiring less RAM.
This application note includes a script for an Octave program.
Octave is a free
(GNU/GPL license) computer program for
numerical computations. This Octave script can compress
scripts and export the results to the C code with decompressi
procedures. The resulting C code
p
Further Optimizations ............................................................... 19
References and Licensing Information .................................... 19
Rev. 0 | Page 2 of 20
Page 3
Application Note AN-1050
ABOUT THE SCRIPTS
BASIC KNOWLEDGE
The compression method described in this application note is
intended to be used with sets of scripts constructed as shown in
the Construction of the Script section. One I
three values:
• device address (to address the device on the I
• register address
• value to be written to the register
Usually scripts provided with evaluation boards by Analog
Devices use ascending order by I
2
C writes. This means that
writes to the same device are in ascending order of register
addresses, such as:
• 42 00 AB
• 42 01 CD
• 42 02 EF
This not accidential; the order of writes makes compression
more efficient because it is more likely to find the same pattern
across various scripts. Note that it is unlikely to find the same
write to the same register of the same device, such as:
• 42 03 04
• 42 03 08
This increases the probability of the same sequences of writes
occurring in different scripts. This is why this application
note describes algorithms in which scripts are checked for
occurrence of sequences of four identical writes, as shown in
Figure 2.
Storing large sequences (of four writes) that are common for
various script big blocks is beneficial to the microcontroller
side. These common blocks (also called keys) can be stored as
a continuous array in a C program. Thus, each key is easily
addressable. This ease of addressing the keys eliminates many
pointers that would otherwise have to be used in the decompresssing algorithm. Each constant pointer requires memory.
CONSTRUCTION OF THE SCRIPT
The Octave script that is used for compression requires an
original set of scripts to be stored in a file in a particular way.
Each original script starts with a header (the first line) containing the characters ## at both the beginning and the end of the
line. The next line in the script is a small header that must
contain colons at both the beginning and at the end of the line.
The following line, the third line, contains proper I
such as:
42 05 02 ; Prim_Mode = 010b for GR
where:
42 indicates the device’s 8-bit, I
2
C address (0x42).
05 is the 8-bit, register address (0x05).
02 is the 8-bit value (0x02).
Prim_Mode = 010b for GR is an optional, user-defined
comment.
Note the spaces and semicolon in the equation. The last line of
the script is single word End, without any spaces. Scripts are
split by the use of empty lines.
The following pages provide an example portion of the set of scripts
for the ADV7401 evaluation board (EVAL-ADV7401EBZ).
2
C writes,
Rev. 0 | Page 3 of 20
Page 4
AN-1050 Application Note
##CP VGA 640x480##
:640x480 _@ 60 Autodetecting sync source 25.175 MHz out through DAC:
42 05 02 ; Prim_Mode = 010b for GR
42 06 08 ; VID_STD = 1000b for 640 × 480 @ 60
42 1D 47 ; Enable 28 MHz crystal
42 3A 11 ; Set latch clock settings to 001b, Power down ADC3
42 3B 80 ; Enable external bias
42 3C 5C ; PLL_QPUMP to 100b
42 6A 00 ; DLL phase adjust
42 6B 82 ; Enable DE output, swap Pr& Pb
42 73 90 ; Set man_gain
42 7B 1D ; TURN OFF EAV & SAV CODES Set BLANK_RGB_SEL
42 85 03 ; Enable DS_OUT
42 86 0B ; Enable stdi_line_count_mode
42 8A 90 ; VCO range to 00b
42 F4 3F ; Max drive strength
42 0E 80 ; Analog Devices recommended setting
42 52 46 ; Analog Devices recommended setting
42 54 00 ; Analog Devices recommended setting
42 0E 00 ; Analog Devices recommended setting
54 00 13 ; Power-down encoder
74 EE EE ; Power-down HDMI
End
##CP VGA 640x480##
:640x480 _@ 72 Autodetecting sync source 31.5 MHz out through DAC:
42 05 02 ; Prim_Mode = 010b for GR
42 06 09 ; VID_STD = 1001b for 640 × 480 @ 72
42 1D 47 ; Enable 28 MHz crystal
42 3A 11 ; set latch clock settings to 001b, Power down ADC3
42 3B 80 ; Enable external bias
42 3C 5C ; PLL_QPUMP to 100b
42 6A 00 ; DLL phase adjust
42 6B 82 ; Enable DE output, swap Pr& Pb
42 73 90 ; Set man_gain
42 7B 1D ; TURN OFF EAV & SAV CODES Set BLANK_RGB_SEL
42 85 03 ; Enable DS_OUT
42 86 0B ; Enable stdi_line_count_mode
42 F4 3F ; Max drive strength
42 0E 80 ; Analog Devices recommended setting
42 52 46 ; Analog Devices recommended setting
42 54 00 ; Analog Devices recommended setting
42 0E 00 ; Analog Devices recommended setting
54 00 13 ; Power down encoder
74 EE EE ; Power down HDMI
End
Rev. 0 | Page 4 of 20
Page 5
Application Note AN-1050
##CP VGA 640x480##
:640x480 _@ 75 Autodetecting sync source 31.5 MHz Out through DAC:
42 05 02 ; Prim_Mode = 010b for GR
42 06 0A ; VID_STD =1 010b for 640 × 480 @ 75
42 1D 47 ; Enable 28 MHz crystal
42 3A 11 ; set latch clock settings to 001b, Power down ADC3
42 3B 80 ; Enable external bias
42 3C 5C ; PLL_QPUMP to 100b
42 6A 00 ; DLL phase adjust
42 6B 82 ; Enable DE output, swap Pr& Pb
42 73 90 ; Set man_gain
42 7B 1D ; TURN OFF EAV & SAV CODES Set BLANK_RGB_SEL
42 85 03 ; Enable DS_OUT
42 86 0B ; Enable stdi_line_count_mode
42 F4 3F ; Max drive strength
42 0E 80 ; Analog Devices recommended setting
42 52 46 ; Analog Devices recommended setting
42 54 00 ; Analog Devices recommended setting
42 0E 00 ; Analog Devices recommended setting
54 00 13 ; Power down encoder
74 EE EE ; Power down HDMI
End
Rev. 0 | Page 5 of 20
Page 6
AN-1050 Application Note
Note that the device address used in the scripts is always an
even number greater than 0. Odd addresses are used for reading
back from the device, which does not occur in this case. Thus,
Address 0x00 is used as an escape code, a special code used for
decompressing.
COMPRESSION/DECOMPRESSION
The Octave script in the Octave Source Code section compresses the script on the PC side. An output of Octave script
is C code containing compressed data and the decompression
algorithm.
The Octave script algorithm consists of the following steps:
1. The script is loaded into matrices of various dimensions
(size is dependent on length of script).
2. The matrices are searched for common blocks or keys
Once the matrices are formatted and common keys are known,
one can start creating C code and perform a small amount of
post-optimization (post-compression). This post-compression
will:
•write representative end of script code (0xFF), so that the
decompressor can find the end of the script.
•determine if the key_number is smaller than 256. If so, its
representing code (0x00, A, B) can be shorted to 0x00, B,
because A is always 0.
•add C code for the decompressor to the end of the C code.
POST COMPRESSING AN
ARRAY WITH KEYS (GREEN)
MAY NOT BRING RE AL
BENEFIT, BE CAUS E THE
CONSTANT SI ZE OF ARRAY
HOLDS THE KEY.
(4 × 3 = 12 BYTES PER KEY)
Finally, generated C code appears as shown in Figure 4.
USAGE
The user can use code given in the Octave Source Code section.
It consists of six files that should be put in the same folder. Place
the script.txtfile, that is, a set of scripts in a format described in
the following section, in this folder. After running the script,
create the output.c file containing the compressed script
algorithm for decompression and an example of main code.
All listings should be saved to one folder together with the script.txt file containing the script to be compressed. This code was tested
using Octave Version 3.0.3.
MAIN.M
clear;
filename = 'script.txt';
%%%%%% loading the script: %%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% load all scripts - script by script %%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
for i=1:number_of_scripts
cmd = sprintf("[script_%d] = load_script(\"%s\", %d);", i, filename, i);
eval(cmd);
endfor
printf("Scripts loaded...\r\n");
fflush(stdout);
%%%%%%% find same occurances in different scripts %%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
NUMBER_OF_LINES = 4;
key_number = 0;
do % master loop - runs the optimization until no improvement is done
% global_found is a variable to show that any improvement was done in full run
global_found = 0;
for i=1:number_of_scripts
i % print the iteration
fflush(stdout); % update user’s screen
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% check if the script is empty or not: %%
dim = size(current_script_a);
if ((dim==[0,0]) || (dim(1) < NUMBER_OF_LINES))
found = 0;
continue;
endif
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%% looking for the same pattern across matrix %%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
while (start_line + NUMBER_OF_LINES - 1 < dim1)
start_line++; % move the pointer
found = 0; % this pattern (KEY) is not found yet
key_added = 0; % KEY: variable for maintaining keys (KEY not FOUND - so not added yet)
% get part of matrix as a pattern to find in other scripts: %
part_of_script_a = current_script_a(start_line:start_line+NUMBER_OF_LINES-1, :);
%%%% search in other scripts for pattern %%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
for j=i+1:number_of_scripts
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% check if the script is empty or not: %%
dim = size(current_script_b);
if ((dim==[0,0]) || (dim(1) < NUMBER_OF_LINES))
continue;
endif
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
val = find_mat2(current_script_b, part_of_script_a);
if (val != 0)
%% AS PATTERN WAS FOUND IN THE OTHER SCRIPT - %
%%%%%%% - ADDING THE KEY TO KEY LIST: %%%%%%%%
if (key_added == 0)
key_added = 1; % KEY_ADDED
key(++key_number, :, :) = part_of_script_a';
this_key = [0, floor(key_number / 256), mod(key_number, 256)]; % MAX: 65535 KEYS!
eval(sprintf("script_%d = current_script_a;", i));
[dim1, dim2] = size(current_script_a);
end
%% MODIFICATION OF THE SCRIPT %%
current_script_b = fsubst(current_script_b, this_key, val, val+NUMBER_OF_LINES-1);
eval(sprintf("script_%d = current_script_b;", j));
%% ADDING COUNTER OF FOUND LINES
found = found + 1;
global_found = 1;
endif
endfor
endwhile
endfor
until (!global_found)
%%% export file to c-file %%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
script_to_c;
LOAD_SCRIPT.M
function [matrix] = load_script(filename, script_number)
% script_number - number of script (starts from 1) to get
current_script_number = 0;
matrix = [];
if ((fhandle = fopen(filename, "r")) == -1)
return;
else
started_script_line = 0;
while (!feof(fhandle))
text_line = fgetl(fhandle);
if (strncmpi(text_line, "end", 3))
started_script_line = 0;
if (current_script_number == script_number)
return; % needed script has been extracted
endif
%%% Is it first line of new script?: %%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
if ((length(text_line) > 1) && (text_line(1) == "#") && (text_line(2) == "#"))
%%% Is it next line of the same script?: %%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
if ((started_script_line > 2) && (script_number == current_script_number))
new_line = (sscanf(text_line, "%x %x %x"))'; % don’t forget about '
if (started_script_line == 3)
matrix = new_line; % creates matrix
else
matrix = [matrix; new_line]; % appends to already created matrix
endif
endif
endwhile
fclose (fhandle);
return;
endif
endfunction
NUMBER_OF_SCRIPTS_IN_FILE.M
function [number_of_scripts] = number_of_scripts_in_file(filename)
if ((fhandle = fopen(filename, "r")) == -1)
number_of_scripts = -1;
fprintf(stdout, "Error while opening file!");
return;
else
number_of_scripts = 0;
fprintf(fhandle, " unsigned char dev_addr, reg_addr, value; // information ");
fprintf(fhandle, "that has to be passed to I2C function\r\n\r\n");
fprintf(fhandle, " unsigned int char_type = DECOMPR_ADDRESS_OR_ESCAPE; ");
fprintf(fhandle, " // state machine var.\r\n");
fprintf(fhandle, " unsigned char *script = (unsigned char *) scr_addr; // pointer\r\n");
fprintf(fhandle, " unsigned int line_counter = 0; // used to terminate when ");
fprintf(fhandle, "processing of keys (as they do not have END sequence as 0xFF;\r\n\r\n");
fprintf(fhandle, " do {\r\n");
fprintf(fhandle, " switch (char_type) {\r\n");
fprintf(fhandle, " case DECOMPR_ADDRESS_OR_ESCAPE: {\r\n");
fprintf(fhandle, " if ((*script == DECOMPR_TERMINATE_VALUE))\r\n");
fprintf(fhandle, " return;\r\n\r\n");
if (key_number > 0)
fprintf(fhandle, " if ((*script) == DECOMPR_ESCAPE_CODE) {\r\n\r\n");
fprintf(fhandle, " // two versions of code ");
fprintf(fhandle, "(below) requires different offset of pointer:\r\n");
Rev. 0 | Page 16 of 20
Page 17
Application Note AN-1050
fprintf(fhandle, " // (0x00, A, B = 16-bit)\r\n");
fprintf(fhandle, " // (0x00, B = 8-bit code)\r\n");
fprintf(fhandle, " if (DECOMPR_USES_2_BYTE_CODES) {\r\n");
fprintf(fhandle, " decompress(keys[(*(script+1))*256 + ");
fprintf(fhandle, " (*(script+2))-1], 1);\r\n");
The compression algorithm discussed in this application note
provides a
•1.858 compression ratio for a set of 51 scripts for the
ADV7401 evaluation board (4748 bytes were compressed
to 2556)
•5.056 compression ratio for a set of 251 scripts for the
ADV7840 evaluation board (52,088 bytes were compressed
to 10,268)
The compression ratio was calculated using the size of the ROM
of the compiled program.
A KEIL compiler was used for testing with the Analog Devices
ADuC7024 microcontroller.
FURTHER OPTIMIZATIONS
Users may want to optimize a given algorithm. Tips on how to
do this are outlined here.
Usually very large scripts use 200 to 700 keys. Thus, instead of
using three bytes for decoding the address (0x00, A, B), users
may optimize this by simply substituting ESCAPE code so that:
• 0x00, A gives the address of the key between (0 + A)
• 0x01, A gives the address of the key between (256 + A)
• 0x03, A gives the address of the key between (512 + A)
• 0x05, A gives the address of the key between (768 + A)
Because these values (0x01, 0x03, 0x05) are odd, they cannot be
used to store the address of the device.
Users may also want to use histograms to check values.
Various key lengths may also be used, however this requires
significantly more microcontroller resources during
decompression.
REFERENCES AND LICENSING INFORMATION
Octave is available for download free of cost by accessing the
official GNU operating system website. This website also
contains information about Octave licensing.
Users may want to check generated code with the integrated
development environment for C/C++, like Dev-C++. This
information, as well as licensing information, can be found on
the official Bloodshed Dev-C++ integrated development
environment (IDE) website.