Lab Assignment: ADC + PWM

Objective

Implement an ADC driver, implement a PWM driver, and design and implement an embedded application, which uses both drivers. 

This lab will utilize:

  • ADC Driver
  • PWM Driver
  • FreeRTOS Tasks
  • A potentiometer
  • An RGB LED

Assignment

Part 1: Implement an ADC Driver

Using the following header file,

  • Implement adcDriver.cpp such that it implements all the methods in adcDriver.h below.
  • Every method must accomplish its task as indicated in the comments.
  • You may add any other methods to enhance the functionality of this driver.
  • It is recommended that you test your ADC driver with ADC_PIN_0_25 because it is connected to the analog light sensor and this is probably the easiest way to test your driver.

For proper operation of the SJOne board, do NOT configure any pins as ADC except for 0.26, 1.30, 1.31

#ifndef ADC_DRIVER_H_
#define ADC_DRIVER_H_

#include <stdio.h>
#include "io.hpp"


class ADCDriver
{
public:
    enum ADC_PIN
    {
        ADC_PIN_0_25,       // AD0.2 <-- Light Sensor -->
        ADC_PIN_0_26,       // AD0.3
        ADC_PIN_1_30,       // AD0.4
        ADC_PIN_1_31,       // AD0.5
      
        /* These ADC channels are compromised on the SJ-One, hence you do not need to support them
        ADC_PIN_0_23 = 0,   // AD0.0
        ADC_PIN_0_24,       // AD0.1
        ADC_PIN_0_3,        // AD0.6
        ADC_PIN_0_2         // AD0.7
        */
    };

    // Nothing needs to be done within the default constructor
    ADCDriver();
    
    /**
    * 1) Powers up ADC peripheral
    * 2) Set peripheral clock
    * 2) Enable ADC
    * 3) Select ADC channels
    * 4) Enable burst mode
    */
    void adcInitBurstMode();

    /**
    * 1) Selects ADC functionality of any of the ADC pins that are ADC capable
    * 
    * @param adc_pin_arg is the ADC_PIN enumeration of the desired pin.
    *
    * WARNING: For proper operation of the SJOne board, do NOT configure any pins
    *           as ADC except for 0.26, 1.31, 1.30
    */
    void adcSelectPin(ADC_PIN adc_pin_arg);
    
    /**
    * 1) Returns the voltage reading of the 12bit register of a given ADC channel
    *
    * @param adc_channel_arg is the number (0 through 7) of the desired ADC channel.
    */
    float readADCVoltageByChannel(uint8_t adc_channel_arg);
};

#endif

Part 2: Implement a PWM Driver

Using the following header file,

  • Implement pwmDriver.cpp such that it implements all the methods in pwmDriver.h below.
  • Every method must accomplish its task as indicated in the comments.
  • You may add any other methods to enhance the functionality of this driver.
  • It may be best to test the PWM driver by using a logic analyzer
#ifndef PWM_DRIVER_H_
#define PWM_DRIVER_H_

#include <stdint.h>
  
class PWMDriver
{
public:
    enum PWM_PIN
    {
        PWM_PIN_2_0,    // PWM1.1
        PWM_PIN_2_1,    // PWM1.2
        PWM_PIN_2_2,    // PWM1.3
        PWM_PIN_2_3,    // PWM1.4
        PWM_PIN_2_4,    // PWM1.5
        PWM_PIN_2_5,    // PWM1.6
    };

    /// Nothing needs to be done within the default constructor
    PWMDriver() {}

    /**
    * 1) Select PWM functionality on all PWM-able pins.
    */  
    void pwmSelectAllPins();
  
	/**
    * 1) Select PWM functionality of pwm_pin_arg
    *
    * @param pwm_pin_arg is the PWM_PIN enumeration of the desired pin.
    */
    void pwmSelectPin(PWM_PIN pwm_pin_arg);
  
    /**
    * Initialize your PWM peripherals.  See the notes here:
    * http://books.socialledge.com/books/embedded-drivers-real-time-operating-systems/page/pwm-%28pulse-width-modulation%29
    *
    * In general, you init the PWM peripheral, its frequency, and initialize your PWM channels and set them to 0% duty cycle
    *
    * @param frequency_Hz is the initial frequency in Hz. 
    */
    void pwmInitSingleEdgeMode(uint32_t frequency_Hz);

	/**
    * 1) Convert duty_cycle_percentage to the appropriate match register value (depends on current frequency)
    * 2) Assign the above value to the appropriate MRn register (depends on pwm_pin_arg)
    *
    * @param pwm_pin_arg is the PWM_PIN enumeration of the desired pin.
    * @param duty_cycle_percentage is the desired duty cycle percentage.
    */
	void setDutyCycle(PWM_PIN pwm_pin_arg, float duty_cycle_percentage);
  
	/**
    * Optional:
    * 1) Convert frequency_Hz to the appropriate match register value
    * 2) Assign the above value to MR0
    *
    * @param frequency_hz is the desired frequency of all pwm pins
    */  	
	void setFrequency(uint32_t frequency_Hz);
};

#endif

Part 3: Application

In order to demonstrate that both drivers function, you are required to interface a potentiometer and an RGB LED to the SJOne board. The potentiometer ADC input shall control the duty cycle of the RGB LED pwm outputs. Note that an RGB LED has three input pins that you will connect to three different PWM output pins. You must use your own ADC and PWM drivers, as well as your own FreeRTOS task. 

Extra credit can be earned with an interesting/cool/creative RGB output.

While in burst mode, do not wait for the "DONE" bit to get set.

Requirements

  • Using your own ADC Driver, read input voltage from a potentiometer
    • Print the voltage reading every 1s.
  • Using your own PWM Driver, drive an RGB LED.
    • Print the duty cycle of all three RGB pins every 1s.
  • The PWM output to the RGB LED must be dependent on the ADC input from the potentiometer.
  • By varying the potentiometer, you should be able to see changes in the color of the RGB Led.

 

Back to top