MENU

Account

Example 1 – (calculation of the sum of products of two arrays):

The example shows how the DSP module can be used for fast calculation of the sums of products of two arrays. The elements of the arrays are kept in the data memory. The X and Y spaces have been detailed in Chapter 8.{dsPIC30F6014A} program ArraySum; var i : word; arr1 : array[20] of Integer; absolute $0900;// array of 20 signed-integer elements in X space arr2 : array[20] of Integer; absolute $1900;// array of 20 signed-integer elements in Y space // replace $1900 with $0D00 for dsPIC30F4013 MCU begin TRISD := 0; // configure PORTD as output for i := 0 to 19 do // init arr1 and arr2 begin arr1[i] := i+3; arr2[i] := 15-i; end; CORCON := $00F1; // signed computing, saturation for both Acc, integer computing asm mov #@_arr1, W8 // W8 := @arr1, point to a first element of array mov #@_arr2, W10 // W10 := @arr2, point to a first element of array mov #0, W4 // clear W4 mov #0, W6 // clear W6 clr A repeat #20 mac W4*W6, A, [W8]+=2, W4, [W10]+=2, W6 // AccA := sum(arr1*arr2) sftac A, #-16 // shift the result in high word of AccA sac A, #0, W1 // W1 := sum(arr1*arr2) end; LATD := W1; // LATD := sum(arr1*arr2) end.Example 1 presents the progam for calculating the sum of products of the array elements. The elements of arr1 are stored in the X space and the elements of arr2 in the Y space of the data memory. At the start of the program the values of the array elements are initiated.

for i:=0 to 19 do begin arr1[i]:=i+3; arr2[i]:=15-i; end;Before the calculation starts, it is necessary to set the DSP module for signed-integer computing. This is done by writing $00F1 to the register CORCON (CORCON:=$00F1;). At the same time the saturation logic for both accumulators (A nad B) is enabled, even though the accumulator B is will not be used. Table 11-3 gives the meanings of individual bits of the CORCON register. The next step is writing the initial addresses (addresses of the first array elements) of the

mov #@_arr1, W8 mov #@_arr2, W10Since the addresses of the first array elements are saved in the W8 and W10 registers, the process of multiplying and accumulating the partial sums can be started. Of course, the initial value of the accumulator A is set to zero by

repeat #20 mac W4*W6, A, [W8]+=2, W4, [W10]+=2, W6 //AccA:=sum(arr1*arr2)After the inxtruction MAC has been executed, the result is in the lower 16 bits of the accumulator A. The result could be read directly from AccAL, i.e. from address 0x0022 (see Table 11-4c), but it is regular practice to shift the result to AccAH, i.e. perfom the shift left 16 times and then read the result by using instruction SAC. In this way the consequences of an overflow, if it occurs, will be mitigated. In this case no overflow will occur, nevertheless the result is read in a regular way. The shift left 16 times is performed by the instruction:

SFTAC A, #-16The instruction SFTAC with its parameters is described in Table 11-2. After the result has been shifted 16 places to the left, it is read and saved in the W1 register. This is done by the instruction:

SAC A, #0, W1The instruction SAC with its parameters is described in Table 11-2.

{dsPIC30F6014A} program AlternateSum; const Sgn : array[2] of Integer = (1,-1); // Signes for sum var arr : array[14] of Integer;//array of 14 signed-integers in Y space (Y space is default) i : Integer; adr2 : Word; begin TRISD := 0; // Configure PORTD as output for i := 0 to 13 do arr[i] := i+1; // init arr adr2 := @Sgn; // dummy line, just for linking Sgn before usage inside asm block MODCON := $8008; // X modulo addressing, on W8 register XMODSRT := adr2; // XMODSRT points to the start of Sgn array XMODEND := adr2+3; // XMODEND points to the end of Sgn array CORCON := $00F5; // Signed computing, saturation for both Acc, //integer computing, PSV managment asm mov #@sgn, W8 // W8 := @Sgn in X space (mirror), // points to a 1st of 2 elements in Sgn array mov #@_arr, W10 // W10 := @arr, points to a first element of arr mov #0, W4 // clear W4 mov #0, W6 // clear W6 clr A // clear accumulator for computing repeat #14 // 15 iterations mac W4*W6, A, [W8]+=2, W4, [W10]+=2, W6 // AccA := sum(Sgn*arr) sftac A, #-16 // shift the result in high word of AccA sac A, #0, W1 // W1 := sum(Sgn*arr) end; LATD := W1; // LATD := sum(Sgn*arr) end.Example 2 shows the method of using modulo addressing, described in Chapter 8, Section 8.3 and PSV management, described in Chapter 11, Section 11.2. Constants +1 and -1 for multiplying the elements of the array arr are saved in the program memory. The advantage of this approach is a reduction in using the data memory. It is particularly suitable when several arrays having constant elements should be saved. Then, the use of the program memory is recommended. The data memory should be used when the array elements are not constants (unknown at the moment of compiling) or if the program memory is full (a rare event). Addresses in the program memory are 24-bit, whereas in the dtata memory are 16-bit. For this reason it is necessary to perform mirroring, by using PSV management, in the upper block of the data memory (addresses above $7FFF). The mirroring is performed in two steps:

- Write in the PSVPAG register the corresponding value (see Figs. 11-3 and 11-7)
- PSV management is enabled by setting the PSV bit (CORCON<2>, see Table 11-3).

ptr:=@Sgn; //ptr points to Sgn (24-bit address) adr:=Hi(ptr); //Get upper Word (16 bits) adr2:=adr and $00FF; //Only lower 8 bits are relevant PSVPAG:=adr2; //Load PSVPAG adr2:=ptr and $FFFF; //Get lower Word (16bits). Mirrored address in X space adr2.15:=1; //Upper data-MEMThe variables ptr and adr are 32-bit long (LongInt). When this part of the code is executed, the PSVPAG register will contain the corresponding value and in adr2 will be the address of the first element of the constant array. The array arr comprises 14 elements and array Sgn only 2. In order to calculate the required sum, modulo addressing should be used for the Sgn array. This is enabled by writing 0x8008 in the MODCON register.

MODCON:=$8008This instruction enables modulo addressing in the X space via the W8 register. The structure of the MODCON register is shown in Chapter 8, Table 8-3. After modulo addressing has been enabled, it is necessary to define the initial and final addresses of this addressing by writing the corresponding values to the XMODSRT and XMODEND registers. The initial address of the constant array contained by adr2 is written to the XMODSRT register. The address of the last byte of the constant array, i.e. adr2+4-1 (+4 because two elements occupy 2 locations (bytes) each and –1 to obtain the address of the last byte) is written to the XMODEND register.

XMODSRT:=adr2; XMODEND:=adr2+3;The next step is setting the required bits in the CORCON register. The structure of the CORCON register is shown in Table 11-3. For the signed computing (positive and negative numbers), enabled saturation logic for both accumulators, enabled saturation logic during writing to the data memory, integer computing and enabled PSV management the value 0x00F5 should be written to the CORCON register. Enabling the saturation logic for accumulator B is superfluous, but it is inserted in the example to show that the saturation logic can be enabled for both accumulators simultaneously. After the corresponding value has been written to the CORCON register, the initialization of the W4, W6, W8 and W10 registers is performed. The registers W4 and W6 are set to zero, whereas in the registers W8 and W10 are written the addresses of the first elements of the arrays Sgn and arr, respectively.

CORCON:=$00F5; asm mov #@_adr2, W8 mov [W8], W8 mov #@_arr, W10 mov #0,W4 mov #0, W6The initial value of the accumulator is set to zero by the instruction clr A. After that, the computing may start.

clr AThe repeat loop is used and it is executed 15 times. By performing mac instruction in the W4 and W6 registers the first elements of the arrays are written and then the 14 partial sums are calculated. The consequence of enabling modulo addressing is that the elements of the array Sgn 1,2,1,2,... will be read alternately.

repeat #14 mac W4*W6, A, [W8]+=2, W4, [W10]+=2, W6After the loop is completed, the result is in the lowest 16 bits of the accumulator A. This result can be read directly from the address 0x0028. Another approach is used in the example in order to illustrate the use of instructions sftac and sac. These instructions are described in Table 11-2. At first, by using instruction sftac, the result is shifted to the middle 16 bits of the accumulator A. Then, by instruction sac, the result is written to the W1 register and from there forwarded to the port D.

sftac A, # - 16 sac A, #0, W1 end; LATD:=W1;

{dsPIC30F6014A} program Mean; var arr : array[15] of Integer; // Array of 15 signed-integer elements i, MeanRes : Word; procedure MeanVar(ptrArr : Word; Len : Word; ptrMean : Word); begin CORCON := $00F1; // Signed computing, saturation for both Acc, integer computing asm mov [W14-8], W10 // W10 := ptrArr mov [W14-10], W7 // W7 := Len sub W7, #1, W2 // W2 := Len-1 clr A repeat W2 add [W10++], #0, A // A := sum(arr) add W7, #1, A // A := A + (Len/2) for div's lack of rounding ... sac.r A, #0, W3 // W3 := round(AccA) repeat #17 // 18 iterations of signed-divide. Result in W0 div.s W3, W7 // W0 := sum(arr)/Len mov [W14-12], W4 // W4 := ptrMean mov W0, [W4] // Mean := Mean(arr) end; end; begin TRISD := 0; // Configure PORTD as output MeanRes := 0; for i := 0 to 14 do arr[i]:=i; // Init arr MeanVar(@arr, 15, @MeanRes);// call subroutine LATD := MeanRes; // Send result to LATD end.The main program is very simple. After setting port D as output and initializing the input array, the procedure for calculating mathematical expectation is called. The result is then sent to port D.

TRISD := 0; // Configure PORTD as output MeanRes := 0; for i := 0 to 14 do arr[i]:=i; // Init arr MeanVar(@arr, 15, @MeanRes);// call subroutine LATD := MeanRes; // Send result to LATDThe procedure for calculating mathematical expectation has only 3 parameters. The first parameter is the address of the first array element (ptrArr = @arr). The second parameter is the number of array elements (Len = 15). The third parameter is the address of the variable where the result, i.e. mathematical expectation, should be written (ptrMean = @MeanRes). The procedure consists of three parts:

- Summation of array elements
- Division of the result by the number of array elements
- Saving the result

CORCON:=$00F1;For the signed computing (positive and negative numbers), enabled saturation logic for both accumulators, enabled saturation logic while writing to the data memory and integer computing the value 0x00F1 should be written to the CORCON register. Enabling the saturation logic for the accumulator B is superfluous, but it is inserted in the example to show that the saturation logic can be enabled for both accumulators simultaneously. After the CORCON register is set, the address of ther first array element is written to the W10 register. The number of array elements is written to the W7 register.

mov [W14-8], W10 mov [W14-10], W7Instruction add should be called as many times as there are elements in the array, i.e. the value in the W7 register should be decremented by 1. Since the number of elements will be required later for performing division, the decrementd value is saved in the W2 register. This is done by the instruction.

sub W7, #1, W2Instruction add will be executed the required number of times. The result of each call is the partial sum which is added to the content of the accumulator A. After completion of the loop, the sum of all array elements is in the accumulator.

clr A repeat W2 add [W10++], #0, ATo obtain mathematical expectation, the sum of all array elements should be divided by the number of array elements. During division it is not possible to round off the result to the nearest integer. For this reason to the sum of all array elements the value Len/2 is added first. This is the same as adding the value 0.5 to the result, but this is not possible in this case because of integer computing. Adding the value Len/2 is done by the instruction add W7, #1, A. This instruction adds the value of the register W7 shifted one position to the right, which is analogous to divide by two, to the current value in the accumulator A. After that, the value in the accumulator A is read and divided by the number of array elements. This is done by the instruction sac.r A, #0, W3. Instruction sac.r is described in Table 11-2.

add W7, #1, A sac.r A, #0, W3In the family of dsPIC30F devices there is no hardware division. Division is performed by 18 iterations each calling instruction div in the loop. The result will be saved in the W0 register and the remainder in the W1 register. The sum of all array elements is saved in the W3 register and the number of array elements in the W7 register. Therefore, the instruction div.s W3, W7 is called in the loop. After the loop is completed, the result is saved in the W0 register.

repeat #17 div.s W3, W7Since the value of mathematical expectation is in the W0 register, it is necssary to write this value to the destination address (third parameter of the procedure). In this way the obtained value of mathematical expectation is forwared to the main program for further processing.

mov [W14-12], W4 mov W0, [W4]