The purpose of this exercise is to reinforce understanding of the dsPIC accumulators by examining an example of their use. We will be adding two arrays of numbers and calculating the scalar average of their resulting sum.
| Windows|| Linux|| Mac OSX|
Integrated Development Environment
| Windows|| Linux|| Mac OSX|
Project and Source Files
Open ProjectStart MPLAB® X, then click on the Open Project icon on the main toolbar
Navigate to the the folder where you have saved the downloaded files
Click on the Lab01.X folder.Select Open Project .
Debug ProjectClick on the Debug Project button. This will build and send the program to the simulator. Click on the Halt button. This will stop execution so that we may examine the arrays and their average.
What just happened?
We took a pre-configured MPLAB® X project, which included a complete program, (both C and assembly files included) along with the configuration settings for the tools, and compiled the code contained in the project. After compiling the code, we ran it in the simulator that is built into MPLAB® X. (The simulator is capable of reproducing almost all of the functions of a PIC® microcontroller.)
Using DSP accumulator-based operations, the code performs the steps listed below:
Populate arrayA with 64 values
arrayA[i] = 0x0100 + (rand() & 0x001F);
In this step we are generating 64 random values between 0x0100 and 0x011F (because we have added a pseudo-random integral number in the range between 0 and 0x001F to our original 0x0100).
Populate arrayB with 64 values
arrayB[i] = 0x0040 + (rand() & 0x000F);
In this step we are generating 64 random values between 0x0040 and 0x004F (because we have added a pseudo-random integral number in the range between 0 and 0x000F to our original 0x0040).
After we have populated our arrays, we need to pass those parameters from C to assembly. C functions pass their parameters to other functions (including assembly functions) through the W registers. It is important to note that the W registers are used in the order that the parameters are passed to the function. As we can see from the code above, the first parameter in our average function is arrayA which means that W0 would contain the address of arrayA. The second parameter is arrayB which then goes to W1, and so on.
- Pass to average.s
- W0 : address of arrayA
- W1 : address of arrayB
- W2 : BUFFER_SIZE = 64
In the assembly code below we can observe that the first step is to PUSH our accumulators/registers onto the stack. Then, after configuring and clearing the accumulators, we see our DO loop starts with the first element of arrayA. We proceed to sum that first value into Accumulator A, ACCA; subsequently, we post increment W0 to read the next value of arrayA in the following pass of the loop. We continue adding values into Accumulator A in this manner until we finish with all the elements. We do the same thing for arrayB, except this time we sum its values into Accumulator B, ACCB. We execute this loop 64 times to finally add all the elements in the arrays.
To find the average of the sum of the arrays, we add ACCA and ACCB and save the result in ACCA.(1)
After that, we can right shift A by #6 which is the same thing as dividing by 64 and store that result into the W0 register.
Lastly, we save the 40-bit accumulator into 16-bit result averagedArrays. From the main.c file, we call the average function created in assembly and observe the following results:
To be able to see the results of this lab you will have to follow these steps: