EENG 383

Lab 11 - In-lab activities

Requirements

Working in teams of two, read through the following lab activity and perform all the actions prescribed. You do not need to document bullet items. Make a record of your response to numbered items and turn them in a single copy as your teams solution on Canvas using the instructions posted there. Include the names of both team members at the top of your solutions. Use complete English sentences when answering questions. If the answer to a question is a table or other piece of art (like an oscilloscope trace or a figure), then include a sentence explaining the piece of art. Only include your answers, do not include the question-text unless it is absolutely needed.

Objective

External hardware

This week's lab will focus on generating sine waves using a digital to analog converter built from running a PWM waveform (from ECCP1) through a low pass filter. This is the same technique that you have used in previous labs, so there is nothing really much to talk about here. Let's move on.

Internal Subsystem

We will be using direct digital synthesis (DDS) to generate the sine waves. We will be using a tmr0 delay in our main DDS loop to time the changes to the phaseIncrement and consequently the DC level of the sine wave. In your assignment, you will need to move this loop inside a TMR0 interrupt. Other than the ECCP1 subsystem and its associate TMR2, there is little new that we need to discuss in this section.

Firmware Organization

Let's go through a familiar configuration of the PIC using the following steps.

Firmware Experiments

This lab is all about the firmware, so let's dive in by taking a closer look at the DDS sine wave generated by the inlab code using an oscilloscope configure as follows: Start by connecting a jumper between RC2 and LPF_in.
Ch1 probe LPF_out
Ch1 ground clip Dev board ground loop
Ch1 coupling AC
Ch1 (scale) 500mV
Horizontal (scale) 1 ms
Trigger mode Auto
Trigger source 1
Trigger slope
Trigger level 0V
Trigger coupling HF Reject
Make sure to:

Program operation

Lets start by looking through the code and gathering some important information.
  1. Complete the following table by going through the program and finding the data types of the following variables. From this information determine the fixed point format for each of the variables. If the variable is acting like a regular integer then its fixed point format is "N.0" where N is the number of whole number bits that are used. Hint, look for the shift operation.
    Variable Data type Fixed piont format
    phaseIncrement uint_8  
    phaseAccumulator   
    index   4.0
    sin[]    

Update Rate

Now we are ready to understand the main DDS loop in the code, reproduced for you below.
00.	while (EUSART1_DataReady == false) {                    
01.	    phaseAccumulator = phaseAccumulator + phaseIncrement;
02.	    index = phaseAccumulator >> 4;                            
03.	    EPWM1_LoadDutyValue(sin[index]);
04.	    TMR0_WriteTimer(0xFFFF - RATE); 
05.	    INTCONbits.TMR0IF = 0;
06.	    while (TMR0_HasOverflowOccured() == false);
07.	}
  1. Using the value for RATE given in the #define statement at the top of the program, calculate the delay generated by the code in lines 04 05 and 06. Make sure to show the dimensional analysis as part of your answer.
  2. Use the value of the delay found in the previous problem along with the smallest phaseIncrement (remember that a bit i positions to the right of the fixed-point decimal point have value 2-i) to determine the frequency resolution of this DDS configuration.
Use the "+" and "-" commands to set the phaseIncrement to 3. Use "s" to produce a sine wave and view it on the oscilloscope. Measure the frequency of the sine wave using the oscilloscope as already setup. You may want to use the averaging function to get a cleaner waveform and improve the accuracy of your measurement. Acquire → AcqMode → Averaging → #Avgs: 128. When you do this you will notice that the waveform updates occur much more slowly and morph whenever you change the frequency. However, you will be able to measure incredibly small amplitudes in this mode,
  1. Complete the following table by changing the phaseIncrement In the "Printed frequency on terminal" column put the value displayed on PuTTY when you press the "s" key. In the "Frequency on scope" put the averaged frequency measured by the oscilloscope. In the "Hz/phaseIncrement" column put the ratio of the oscilloscope measured frequency divided by the phaseIncrement. Note that this column is the observed frequency resolution of the DDS system because it will tell you how many Hz the output waveform changes for a LSB change in the phaseIncrement.
    phaseIncrement Printed frequency on terminal Frequency on scope Hz/phaseIncrement
    3      
    5      
    7      
    9      
    13      
    17      
    23      
    27     30-ish

Tune the update rate

From the previous experiments you saw that the theoretical frequency resolution was close, but not an exact match for the observed frequency resolution. The discrepancy is a result of the added time required to perform the computations in the main DDS loop (lines 01-05 in the code snippet above). However, this bothers me less than the fact that I want the observed frequency resolution to be related to the phase increment by some power of 2. Huh?

In my program, I displayed the frequency of the waveform to the terminal user using the expression:
printf("Generating a %d Hz sine wave\r\n",phaseIncrement<<5);
I approximated the displayed frequency by multiplying the phaseIncrement by an approximation of the frequency resolution, 32 Hz. Now, you know that the observed frequency resolution is 30-ish, you could do one of two things…

At first glance, the easy thing would be to change the print statement:
printf("Generating a %d Hz sine wave\r\n",phaseIncrement*30);
While this solution is quick and easy to implement, there is another approach which will result in less work for the microcontroller.

  1. Let's change the update rate (using the RATE constant) so that the frequency resolution of our DDS system is exactly 32Hz. Do this systematically by setting up a ratio of the actual RATE value over the observed update rate (reciprocal of the observed frequency resolution) and making this ratio equal to the unknown RATE over the target update period, reciprocal of 32 Hz). Show your work in the form of a ratio.
  2. After changing the update rate, calculate the percentage error of the terminal frequency value by computing: % error = 100*(terminal frequency - oscilloscope frequency)/oscilloscope frequency
In this week's lab, I found that I was able to get a frequency resolution of 0.5 Hz. You will have to use the units factoring to determine a close value for the update rate and then tune the value (using this method) to get the frequency resolution spot on. It's worth the effort because it makes converting between phaseIncrement and frequency so much easier.

Sweep calculation

First off, make sure to turn off the averaging mode from the oscilloscope before going any further. The code for the frequency sweep operates by incrementally increasing the phaseIncrement through some duration. In your program, the core-loop of the frequency sweep function is cut-and-paste from the sine wave generator function. Around this core-loop is a loop that holds each phaseIncrement for a delay given by timer 1.
  1. Use the values for START_PHASE, END_PHASE and the delay created by timer 1 to determine the amount of time that it takes for the outer sweep loop to iterate through all the phaseIncrements. State your answer using dimensional analysis. You will need this equation to complete this week's lab. If you are struggling to figure out how to do this, try finding answers to the following questions.
    • How many times does the outer loop need to loop?
    • How long does it take the inner loop to loop?
  2. Carefully setup your oscilloscope to capture a whole frequency sweep. Do this by setting:
    • the vertical adjust to 500mV per division and
    • the horizontal adjust to 100ms per division and
    • the trigger level to around 100mV above "ground"
    • set the trigger horizontal position on the second reticule.
    Include a screen shot of the sweep as your answer to this question.
  3. Why is the amplitude across the frequency sweep changing? Explain how, knowing the starting and ending frequencies, you could predict the change in amplitude. Hint, think about the hardware we are using to transform our PWM signal into a smooth sine wave.
  4. What is the measured duration of the frequency sweep from the oscilloscope? Compute the percentage error of the theoretical value using the equation from earlier in this lab.

Math time

I found that performing the computation to make a frequency sweep to be the most challenging aspect of this week's lab. Part of that difficulty was the multiplication and division, and printing of 32-bit values. I hope that these questions point you in the right direction so that you don't get caught-up fighting with the compiler like I did.

For the take-home part of the lab, you will need to change the delay inside the frequency sweep (TMR1) in order to control the time that the sweep takes. In order to calculate the delay for the frequency sweep you will need to perform a computation similar to the one given in the "m" command. The computation results in the number of timer counts need for each phaseIncrement of the sweep; a uint16_t typed variable that is called d16 in the inlab program. You need to be careful with your code so as to prevent unnecessary overflow. To this end, I have calculated d16 in two different ways. A paranoid version (that works) where each uint16_t variable is cast as a uint32_t prior to performing any computation. The second version is more casual and reflects what one might initially be tempted to do when writing this program. You will compare the results of these two computation styles and compare them to an authority to determine which does a better job. By a better job, I mean overflows less frequently.

In order to determine the correctness of your calculations, you will need an authority. In our case, you will use the Windows calculator as the authority that generates the true, valid solution to our set of calculations. Launch the windows calculator by having windows search for it. Press the Windows key on your keyboard, type "calc", wait a moment for the search bar to return its top reference as Calculator, then hit <Enter>. When the Calculator launches, click on the 3 short horizontal bars near the upper left corner of the Calculator window and select "Programmer". Click on one of the bases, "Hex" for example, to enter numbers in that base. As you enter digits, your value will be converted into the other three bases.

  1. Complete the following table by programming in the values for the a16, b16 variables in the assignment statements in the case 'm' of your inlab program (around lines 168, 169) and recording the output in the corresponding rows below. Compare the results by performing the calculation using the windows calculator. If the result generated results in an overflow, then indicate this in the entry.
    a16 b16 d16 - paranoidd16-casualAuthority
    2000 1000      
    2000 200      
    1000 200      
    2000 100     10,000
    2000 10 34,464 (overflow)    
    100 200      

Build a sine LUT

You are going to need to build a 64 sine-LUT for this week's lab While you could do this with a calculator, I think that using the following procedure in Excel will save you a lot of time. I'll walk you through the process in the following steps: