CSE466 Lab 3: “Pulse Width Modulation”

Objectives

The goal of this lab is to generate various colors using a tri-color LED. To select the color to be output we will create a virtual knob by measuring accelerometer readings through pulse width measurements. In addition, you will also use pulse width modulation to control the brightness of the LEDs. In this lab you will learn the following:

  • how to read an accelerometer reading via pulse width measurement ;
  • how to use the input capture on the 16-bit timer on the ATmega16 to do so; and
  • how to adjust the intensity of a light using pulse width modulation.

Important Warnings

Do NOT do either of these two things:

  1. The ADXL202EB (the accelerometer evaluation board used in the lab) is not reverse polarity protected. Do not reverse the +5V and ground terminals as it will damage the ADXL202EB and make the part unusable.
  2. Do not drop the ADXL202EB on a hard surface as it may generate several thousand g's of acceleration, enough to damage the accelerometer.

Hints

  • Take this lab step by step and incrementally test your code to make sure that it is working as you expected. Coding the entire project first then trying to debug a problem can be challenging without the usual forms of debugging. Make sure to test pieces of code one at a time and convince yourself that they are working before moving on to another piece.
  • The lab is broken up into multiple parts to make the lab simpler with smaller/simpler tasks that will build to the final result. It is a good idea to save a copy of your code after each step. If for some reason you are unable to complete the lab partial credit will be given for each completed step.
  • Utilize the 7-segment LED displays for debugging. WARNING: If you update the 7-segment LED displays each time through your main loop you might not be able to read the numbers because it will be changing the number on the order of milliseconds.
  • With a small enough period, a human eye should not be able to perceive any flickering of the LED when the button is not pressed. If you are seeing flickering it is most likely timing related, such as an interrupt being to long. You should try to eliminate any flicker from your LED's. However, you should focus on completing the lab first instead of spending huge amounts of time trying to troubleshoot. 
  • Focus on making your system have a reasonable interface. Do not get stuck trying to get timing calculations to work out perfectly. The accelerometer is inherently noisy. The important thing is to create an interface that “feels” right to a human. People will not notice timing errors on the order of microseconds (maybe not even a few milliseconds depending on where it is in the code).
  • We are using 2g accelerometers – that means they detect accelerations up to two times the force of gravity. The parts should not be subjected to too much more than this – being dropped or banged on a hard surface. Your calculations can assume that you are only using gravity to determine how far a user has turned the accelerometer to the left or right. By using this assumption your calculations will be incorrect because they will not take into account the force you yourself apply in starting and/or stopping the accelerometer. Treat this(the starting/stopping acceleration) as noise as it is difficult to account for this systematically in your calculations.
  • DON’T USE FLOATING POINT NUMBERS.

Suggested Reading

Resources

Brief introduction to AVR Programming
avr-gcc manual - located at: C:\WinAVR\doc\avr-libc\avr-libc-user-manual\index.html
Application notes section for the AVR 8-bit RISC family
Accelerometer(ADXL202)Datasheet  (also in CoursePak)
AccelerometerApplication Note on using the Duty Cycle Output
Tri-Color LED Datasheet Note: We will be using Common Anode LEDs.
Color Applets

Suggested Steps

PART 1:

  1. Remove the 7-segment LED on PORTC/D.
  2. Add the tri-color LED to your breadboard by connecting the Common Anode to Vcc, the red LED to pin21 (use a 560 ohm current limiting resistor), the blue LED to pin 19(use a 300 ohm current limiting resistor), and the green LED to pin 18 (use a 300 ohm current limiting resistor). NOTE: To aid in debugging you may want to add 3 separate LEDs in parallel to your tri-color LED to see the light level of each color segment; however, make sure the parallel LED is separate (i.e. has its own current limiting resistor).
  3. A cable has been provided for your accelerometer module, using black wire for ground, red for +5v, yellow wire for the Y-axis output, white wire for the X-axis output, and blue wire for the button (the other end of the button is connected to ground).
  4. Wire your accelerometer module into your breadboard with the cable you made. Attach the Y-axis output to ICP1 (pin 20) and the blue wire to the INT1 pin to detect button presses. Remember to add a pull-up resistor to the button circuit. Plug the X-axis output into an unused row on your breadboard as we will use it later in the lab.
  5. Refer to page 9 of the accelerometer datasheet in your coursepak to determine what resistor to add to the accelerometer board at R1. R1 should be chosen such that the period of the accelerometer’s PWM period is approximately 4ms. Trim the leads to fit.
  6. Review important warnings (YES, AGAIN) and apply power to the circuit. Observe the y-axis output with an oscilloscope. Measure the period and min-max duty cycle.

Complete Worksheet.

PART 2:

  1. Download the PWM sample code. It uses the output compare capability of timer 2 to generate a PWM wave to control the brightness of an LED connected to OC2 (pin 21). Modify PWM sample so that you can control the LED brightness by adjusting the value of a potentiometer.
  2. Implement a program that uses timer 1 input capture mode to determine the positive duty cycle. To do this, time the length of the positive pulse of your accelerometer (rising edge to falling edge) and the length of the period (rising edge to next rising edge). Use the 7-segment LED to display a ‘1’ when the accelerometer has a duty cycle less than 50% and a ‘2’ when the accelerometer has a duty cycle greater than 50%.
    NOTES:
    • You should choose as small a pre-scalar factor as possible for Timer 1 to increase the accuracy.
    • Use TCNT1 and ICR1 to access 16-bit values instead of using the 8-bit registers (i.e. ICRL & ICRH and TCNT1L & TCNT1H)
    • Remember to set TCNT1=0 when you want the counter restart at 0. The input capture interrupt does not reset TCNT1 to zero automatically.
  3. Combine step 1 and 2 so that when you turn the accelerometer to the right it makes the LED brighter and when you turn it to the left it makes the LED dimmer. NOTE: If you turn the accelerometer-based virtual switch past 90 degrees it will start to decrease again. Use the one 7-segment LED displays to output the most significant byte of your light level (the value of OCR2) in hex.
  4. Modify your code so that the brightness only changes when the button on the virtual knob is pressed. (Remember to de-bounce your button.) When the button on the accelerometer board is pressed the user could be at any angle so you must record the current position as a reference to determine if the user is turning right or left. Use the one 7-segment LED displays to output the most significant byte of your light level (or value of OCR2) in hex.

PART 3:

  1. You will need to manually generate three separate PWM signals to drive the tri-color LED. Use timer0 to generate 3 separate PWM signals for each segment. A period of <15ms should not be visible to a human. (For the end of the lab we encourage using a period less than 15 ms, but start at 15 ms and then reduce it as a smaller period will be more taxing on the processor.)
  2. Use the potentiometer and the ATMega16's ADC to test your manual PWM signal. Use the ADC readings (0-255) to control the LEDs brightness. You might want to avoid using free-running mode to trigger the ADC as it might cause timing problems. A good auto-trigger is Timer0 output compare (same interrupt that should be generating your PWM).

PART 4:

  1. Use the input capture of the accelerometer from Part 2 to drive the tri-color LED instead of the ADC (Part 3).

PART 5:

  1. Plug the x-axis of the accelerometer into INT0 (pin 16)
  2. Use INT0 and Timer2 to create a manual interrupt capture routine to determine the positive duty cycle of the x-axis.
  3. Use the accelerometer x-axis, the accelerometer y-axis, and ADC to drive each segment of the tri-color LED. 

PART 6:

GOAL: To generate various colors on the tri-color LED using the accelerometer to select color and the potentiometer to adjust brightness. A user should be able to press the button and move the accelerometer until they find a color they want. On button release the H & S value should lock in. A user should be able to update the brightness of the color they choose by adjusting the potentiometer at any time.

  1. Use the provided HSV to RGB code to control the tri-color LED. (Note: The skeleton code being provided is formatted to help minimize potential timing problems. We highly suggest you bring your code into the skeleton, not the other way around.) Code
    H->x-axis
    S->y-axis
    V->ADC value of potentiometer (this controls brightness)
  2. Make sure to adjust the three constants (COLOR_SPACE_MAX, X_BASE, Y_BASE) to get the highest possible color spectrum.
  3. To eliminate gitters/flickers make sure to average your values (H, S, & V).
  4. The color should only change while the user holds the button on the accelerometer down. Brightness should update anytime the value of the potentiometer is changed.
  5. Suggested timer uses:
  • Timer0 -> used to generate the 3 PWM’s needed for the tri-color LED
  • Timer1 -> input capture for the y-axis (possible button polling)
  • Timer2 -> used with INT0 to perform input capture for the x-axis

5.  After this is working (and you’ve added averaging) you can drop the PWM period to further reduce flickering. However, if the period is dropped too far flickering will increase.

Question 1: Describe the differences between the HSV and RGB color spaces. In general, how can you convert between the two.

Question 2: Describe why the code in your interrupt handlers could not be located in the main body of the program. Basically explain your design and why it was important for the specific code to be in an ISR.

Deliverables

For all files turned in, the comments at the top of the file should contain:

  • Both partners' full name, login and student number.
  • The lab number and the part of the lab (e.g. “Lab 3”).
  1. Demonstrate part 6 to a TA. You can either do this during this lab, or during the first 1/2 hour of the next lab.
    • You will not receive full points if there is noticeable flicker on any of your LED's when the button is not pressed.
    • The light levels of the LED's should not change until the button is pressed or your potentiometer is adjusted (which should only adjust the brightness).
    • It should be possible to display all major colors on your Tri-Color LED (The more distinct colors the better!).
  2. Turn in hardcopy of your commented C code.
    • Make sure that the code in your interrupt handler is as minimal as possible. It is fine to update state or do a little bit of work in the interrupt handler. We will grade on how you designed your program to minimize code in the interrupt handler.