Created by Scott Schmit, last modified on Nov 13, 2013
Purpose
Pulse-Width-Modulation (PWM) is used in a wide variety of applications. The purpose of this page is to provide a simple PWM example for PSoC devices. PSoC Creator, which is a free development tool from Cypress for PSoC 3, 4, 5, and 5LP devices, was used for firmware development for this project. The PSoC4 Pioneer Kit was used as the platform for this demo. However, any PSoC device can use the code for this project.
Note: This project also implements a 16-bit Timer. Click here for a PSoC Timer example
Project Goals
The following goals will be accomplished in this project. If the user simply wants to browse through the application code for this project, feel free to skip ahead.
- Start a project from scratch in PSoC Creator
- Add/Configure a PWM component to the design
- Add a Clock component to the design
- Add/Configure a Timer component to the design
- Add an Interrupt component to the design
- Add/Configure a Digital Output pin to the design
- Select which pins are used to control LED
- Provide/explain application code
Project Requirements
The following tools were used for this project:
- PSoC Creator - Free firmware development software provided by Cypress. Version 3.0 was used for this project.
- PSoC4 Pioneer Kit - Development platform for PSoC4 devices.
Procedure
Start a PSoC Creator Project
- Open PSoC Creator
- Navigate to File → New → Project
- Select “Empty PSoC 4 Design”
- Name the project “Timer_PWM”, select a location to save the project, and click “Ok”
- This will bring you to the schematic view of the project where you can click and drag desired components into your design. If you do not see a blank schematic page, double click “TopDesign.cysch” from the Workspace Explorer window
Add/Configure a PWM Component
- In the Component Catalog window, in the Digital → Functions folder, click and drag the “PWM” component onto the page. For this project, a Fixed-Function (UDB) PWM component was used.
- Double click on the component to bring up the Configuration window. For this project, the default name “PWM_1” was used. The Resolution was set to 16-Bit with 2 outputs. The Period was set to 12000. CMP Value 1 was set to 8000 and CMP Value 2 was set to 4000.
- Click “Apply” to apply any changes and click “Ok” to close the Configuration window.
Add a Clock Component
- In the Component Catalog window, in the System folder, click and drag the “Clock” component onto the page. For this project, a Fixed-Function (UDB) PWM component was used.
- Double click on the component to bring up the Configuration window. For this project, the default name “Clock_1” was used. The Frequency was set to 12MHz.
- Click “Apply” to apply any changes and click “Ok” to close the Configuration window.
- Connect the Clock component to the PWM component. Press “w” on the keyboard, click on the Clock component, and then click on the Clock input of the PWM component.
Add/Configure a Timer Component
- In the Component Catalog window, in the Digital → Functions folder, click and drag the “Timer” component onto the page. By default, a 24MHz clock is attached to the component.
- Double click on the component to bring up the Configuration window. For this project, the following timer settings were used:
- Resolution: 16-bit (counter value can be 0~65535).
- Period: 24000 (with 24MHz clock, period = 1ms)
- Trigger Mode: None
- Capture Mode: None
- Enable Mode: Software Only
- Run Mode: Continuous
- Interrupts: None
- Click “Apply” to apply any changes and click “Ok” to close the Configuration window.
Add Interrupt Component
- In the Component Catalog window, in the System folder, click and drag the “Interrupt” component onto the page.
- Double click on the component to bring up the Configuration window. Change the name to “ms_isr”.
- Click “Apply” and “Ok” to close the Configuration window.
- Connect the ISR component to the “tc” output of the 16-bit Timer using the “w” hotkey.
- Add another ISR component called “tc_isr” and connect it to the “tc” output of the PWM module.
- Add another ISR component called “blue_isr” and connect it to the “pwm1” output of the PWM module.
- Add another ISR component called “red_isr” and connect it to the “pwm2” output of the PWM module.
Add a Digital Output Pin
- In the Component Catalog window, in the Ports and Pins folder, click and drag the “Digital Output” component onto the page.
- Double click on the component to bring up the Configuration window.
- Rename the component “Blue_LED”. Ensure “Digital Output” is checked and uncheck “HW Connection”.
- Under the “General” tab, select “Strong Drive” as the Drive Mode and “High (1)” as the Initial State.
- Click “Apply” to apply any changes and click “Ok” to close the Configuration window.
- Add another Digital Output pin named “Red_LED” with the same settings.
Select LED Pins
- In the Workspace Explorer window, click on “Timer_PWM.cydwr”. This is where you can define which pins of the PSoC device will be used for LED control.
- You should see 2 signals called “Blue_LED” and “Red_LED” with drop-down arrows next to them. The drop-down arrows can be used to select a Port/Pin for each LED signal. Select P0[3] as the “Blue_LED” control pin. P0[3] is connected to the Blue LED on the Pioneer Board. Select P1[6] as the “Red_LED” control pin.
- Save and close the “PWM_Example.cydwr” tab.
Build the Project
- Build the project. This will auto-generate functions for each component which you can execute from application code.
Example Code
The following code block demonstrates how PWM can be used to control the intensity of two LEDs.
#include <project.h>
#define ON 0
#define OFF 1
#define UPDATE_PERIOD 4 //ms
#define COMPARE_VAL_MIN 51
#define COMPARE_VAL_MAX 11949
uint16 ms_count = 0;
uint16 comp_val1 = 50;
uint16 comp_val2 = 11950;
uint8 increment = 1;
CY_ISR(BLUE_ISR) {
Blue_LED_Write(ON);
}
CY_ISR(RED_ISR) {
Red_LED_Write(ON);
}
CY_ISR(TC_ISR) {
Blue_LED_Write(OFF);
Red_LED_Write(OFF);
}
// This ISR updates the compare values at a frequency
// defined by UPDATE_PERIOD
CY_ISR(MS_ISR) {
ms_count++;
if(ms_count == UPDATE_PERIOD) {
if(increment) {
comp_val1 += 50; // increment compare value 1
comp_val2 -= 50; // decrement compare value 2
}else{
comp_val1 -= 50; // decrement compare value 1
comp_val2 += 50; // increment compare value 2
}
if(comp_val1 < COMPARE_VAL_MIN) { // make increment "true"
increment = 1;
}
if(comp_val1 > COMPARE_VAL_MAX) { // make decrement "true"
increment = 0;
}
ms_count = 0; // reset ms counter
}
}
int main()
{
Timer_1_Start(); // Configure and enable ms timer
PWM_1_Start(); // Configure and enable PWM module
blue_isr_StartEx(BLUE_ISR); // Point to BLUE_ISR to turn on the blue LED
red_isr_StartEx(RED_ISR); // Point to RED_ISR to turn on the red LED
tc_isr_StartEx(TC_ISR); // Point to TC_ISR to turn off both LEDs
ms_isr_StartEx(MS_ISR); // Point to MS_ISR to update the compare values
CyGlobalIntEnable; // Enable global interrupts
for(;;)
{
PWM_1_WriteCompare1(comp_val1); // Write new compare value to PWM output 1
PWM_1_WriteCompare2(comp_val2); // Write new compare value to PWM output 2
}
}
Downloadable Projects
- Timer_PWM.zip (1.3 MB) - This project uses a single PWM (with dual output) to fade the RGB LED from Blue to Red continuously.
- RGB_PWM.zip (1.5 MB) - This project uses 3 individual PWM modules (with single output) to cycle the RGB LED through the entire color wheel.
Questions/Comments
PWM is used in a wide variety of applications like DC/DC power conversion, LED intensity control, and motor control to name a few. I hope this example was helpful for you. For questions or feedback about information on this or any other page, please go to the TechForum: TechForum Thanks for visiting the eewiki!
- Scott