MPLAB® Harmony v2 Ports Project Using chipKIT® WF32
Objective
This example project detects a button press to enable and disable a blinking LED. A push-button switch on the evaluation board is connected to an I/O Port pin on the PIC32.
Two Timer System Service objects are used in this project. One creates a delay (100 ms) used to poll the I/O Port pin connected to the switch. The other creates a delay (50 ms) used to debounce the switch and blink the LED. The Timer System Service object used to poll the switch is always active. The Timer System Service object used to blink the LED and debounce the switch only exists when switch debouncing and LED blinking is needed. This provides an example of how a delay (and its corresponding resources) can be created and deleted during run time.
The code you will add to this example project (as described in the following steps) implements the state machine shown in the diagram below.
You may also be interested in another example project that shows how to blink LEDs at a constant rate: Learn more here.
The "Project and Source Files" download (see below) contains a fully functional project. It can be used as an example and requires no modifications. To gain a deeper understanding of how to use the MPLAB® Harmony framework, we recommend you generate the project and source files yourself by following the step-by-step procedure below.
This image shows the chipKIT® PGM programmer/debugger from Digilent®. Microchip programmer/debuggers (e.g. PICkitTM3) can also be used.
Software Tools
This project has been verified to work with the following versions of software tools:
MPLAB X IDE v3.25, MPLABXC32 Compiler v1.40, MPLAB Harmony v1.07.01
Note: Because we regularly update our tools, occasionally you may discover an issue while using newer versions. If you suspect that to be the case, we recommend that you double-check using the same versions that the project was tested with.
Archived versions of our tools can be found on the following Microchip websites: MPLAB Harmony (see "Archived Downloads" tab) MPLAB X IDE and XC32 Compiler (see "Downloads Archive" tab)
Note that multiple versions of all these tools can co-exist on the same computer.
The contents of the following .zip file need to be placed in this directory. If this is not done, the MPLAB® X IDE will not be able to find all source files, and the project will not build successfully.
The "Project and Source Files" download provides a fully functional project. It can be used as an example and requires no modifications. The following steps below provide instruction on how this project was created.
1
Create a new MPLAB Harmony project
The Target Device used on the chipKIT® WF32 is the PIC32MX695F512.
Before you create a new MPLAB® Harmony project, you must install the MPLAB Harmony Configurator (MHC) graphical user interface. This GUI enables easy addition and configuration of the Harmony library files needed for your application. It also allows MPLAB X IDE to create a new MPLAB Harmony project.
In the MPLAB X IDE, select File > New Project
(or click in the toolbar).
Select the Microchip Embedded category if it is not already selected.
From the Projects list, select MPLAB Harmony Project.
Click Next >.
If you do not see MPLAB Harmony Project option, you have not installed the MHC. Click here for instructions on installing the MHC plugin.
The next window should have the default Harmony Path, Project Location, and Project Path already selected for you. Remember the MPLAB Harmony framework expects to find specific files in specific locations. Do not change these default paths because the project may not build.
After you click Finish, your new project will be opened.
MPLAB® Harmony Project Wizard Details Learn more >
Before creating an MPLAB Harmony Project, the MHC plugin must be installed into the MPLAB X IDE. Click here for instructions on how to install the MHC plugin.
This video will show you how to create an MPLAB Harmony Project in the MPLAB X IDE. For details on how an MPLAB Harmony Project differs from a typical standalone project, click here.
2
Use the BSP to load appropriate default values for the PIC32 core, clocks, and I/O port pins.
Use the MPLAB® Harmony Configurator (MHC) to select the Board Support Package (BSP) for the chipKIT® WF32 board. Choosing this BSP allows MHC to load appropriate default values for this board. These default values configure the PIC32 core, clocks, and I/O port pins for you.
Click on the Options tab in the MPLAB Harmony Configurator window.
Expand the BSP Configuration sub-menu and check the Use BSP? box.
Expand the Select BSP To Use For PIC32MX695F512L Device list and check the chipKIT WF32 Board (PIC32MX695F512L) box.
Feel free to click on the Clock Diagram, Pin Diagram, and Pin Settings tabs to see this BSP's default values. The default BSP selections for the PIC32 core configuration registers can be found by expanding the Device & Project Configuration and PIC32MX695F512L Device Configuration sub-menus.
Click image to enlarge.
Click image to enlarge.
You can modify the default BSP settings if you choose. Modifications to the BSP default values will show as highlighted selections.
3
Use MHC to enable and configure the Timer System Service
You will use the Timer System Service to implement two delay periods. One will blink the LED and debounce the switch every 50 ms, and one will poll the switch every 100 ms.
In the MPLAB Harmony Configurator Options tab, expand the following sub-menus:
Harmony Framework Configuration
System Services
Timer
Check the Use Timer System Service? box.
Check the Interrupt Notification Enabled box.
The "Timer Running Frequency" controls the increment rate for the System Timer counter (1000 Hz = 1 System Timer tick every 1 ms).
The "Internal Time Units (Hz)" controls the decrement rate for the alarm delay period countdown timers (10 000 Hz = 10 decrements per 1 ms).
Click image to enlarge.
Click image to enlarge.
Note how the MHC configuration tree is highlighted to show a change from MHC's default value. The Timer System Service Library is a client for the Timer Driver Library. Checking the Use Timer System Service? box will also automatically check the Use Timer Driver? box (found in: Harmony Framework Configuration > Drivers > Timer) for you. This is MHC's default setting when the Timer System Service is enabled, so this change is not highlighted. You will also use the default settings for the Timer Driver (uses the Timer1 peripheral), so there is no need to configure it.
Open the app.h file, and add the application state names to the enumeration shown below (near line #87). Also comment out the existing APP_STATE_SERVICE_TASKS enumeration. You will not be using this name.
Click image to enlarge.
file: app.h
Add the following application variables to the APP_DATA structure (near line #129):
file: app.h
6
Add application-specific configuration constants to the project in system_config.h.
Open the system_config.h file, and add the following application-specific configuration constants (near line #166):
file: system_config.h
You could have defined these in the application header file (app.h), but defining them in the system configuration header file (system_config.h) allows these macros to change if you plan on using different hardware platforms. The MPLAB X IDE allows one project to support multiple hardware platforms through the ability to include or exclude source files from the project based on the project configuration. The MPLAB Harmony Framework uses this ability to include all source files in one system_config folder while excluding all others (if others exist).
7
Create the callback functions used by the Timer System Service.
You enabled and configured the Timer System Service in a previous step. When you clicked on MHC's Generate Code button, it included the appropriate Timer System Service source files in your project and added code to initialize and configure it per the settings you provided in MHC.
The Timer System Service is used to implement delays and execute functions after specified delay periods. It uses a Timer Driver (is a client to the Timer Driver) to keep track of time. You will use the Timer System Service library to create Timer System Service objects that specify delay periods, and the function names to execute (callback functions) after the delay periods. You will need to create two delay periods (objects) in the following steps:
One to read the voltage level on the I/O Port pin connected to the switch every 100 ms
One to debounce the switch and blink the LEDs every 50 ms.
In this step, you will create the functions associated with these delay periods.
Open the app.c file (found in the Source Files ▶ app ▶ folder), and add the following callback function to poll the switch (near line #93).
file: app.c
Also, add this callback function (near line #123). It performs two tasks:
If the state machine is in a blinking state, the LED will be turned on and shut off every 50 ms.
If a switch press or switch release is detected, it will debounce the switch.
Read the value on the I/O Port pin.
If the correct voltage corresponding to a pressed (or released) switch is read, increment the debounce counter.
If two consecutive correct voltage readings occur (determined by APP_DEBOUNCE_COUNT), the voltage on the pin has stabilized.
Set the flag indicating the switch press (or release) has been confirmed (appData.switchHasBeenPressed = true or false).
Depending on the circuit connected to the I/O Port pin, a switch press will put either a 1 or a 0 on the pin. The callback function will work for both cases as long as you properly declare the value of APP_CN_PRESS_EQUALS_1_OR_0 (declared in system_config.h in a previous step).
The image at the top of this page shows the state machine you are about to add to the project. The APP_Tasks() function implements this state machine.
State Name
Description
APP_STATE_INIT
This state initializes appData.pressDetected and appData.switchHasBeenPressed to true, and transitions to the APP_STATE_LED_OFF_NO_PRESS_DETECT state. These variable settings in this state force the state machine into the APP_STATE_BLINK_LED_NO_PRESS_DETECT state to blink the LEDs.
APP_STATE_LED_OFF_NO_PRESS_DETECT
In this state, the LED is off. The APP_TimerCallBack1() function tests for a switch press every 100 ms. When it detects a switch press, the pressDetected flag is set. This causes a new Timer System Service to be created with a 50 ms delay. This delay is needed to debounce the switch and to create the LED on and off times so you can see it blink. SYS_TMR_ObjectCreate() passes the delay time in ms (defined by APP_LED_BLINK_DELAY) into the function. It also passes the name of the callback function (APP_TimerCallBack2()) to run when this time has passed. A pointer (handle) to this new System Timer object is returned by the function so we can access it later.
After the System Timer object is successfully created, it will transition to the next state: APP_STATE_LED_OFF_DEBOUNCE_PRESS.
APP_STATE_LED_OFF_DEBOUNCE_PRESS
This state keeps the LEDs off while it waits for a switch press to be confirmed (waits for the switch debounce to complete). This happens when appData.switchIsPressed is set to true. When the press is confirmed, it transitions to APP_STATE_BLINK_LED_DEBOUNCE_RELEASE.
APP_STATE_BLINK_LED_DEBOUNCE_RELEASE
Now that the switch is confirmed as pressed, the LED will start to blink. Before you can detect another press, you must first confirm a switch release (no press). When the state machine is in this state, the APP_TimerCallback2() function will debounce the press release. When the release is confirmed, the switchIsPressed flag will be cleared. This causes the state machine to advance to the APP_STATE_BLINK_LED_NO_PRESS_DETECT state.
APP_STATE_BLINK_LED_NO_PRESS_DETECT
This state blinks the LED while waiting for a press to be detected. The APP_TimerCallback1() function polls the switch every 100 ms. If it detects a switch press, it will set the pressDetected flag, causing the state machine to advance to the APP_STATE_BLINK_LED_DEBOUNCE_PRESS state.
APP_STATE_BLINK_LED_DEBOUNCE_PRESS
This state keeps the LED blinking until a switch press is confirmed. Once a press is confirmed, it will shut the LED off, and transition to the APP_STATE_LED_OFF_DEBOUNCE_RELEASE state.
APP_STATE_LED_OFF_DEBOUNCE_RELEASE
In this state, the LEDs are off, and the switch release has to be confirmed. The APP_TimerCallback2() function will debounce the press release and clear the switchIsPressed flag.
When this happens, this System Timer Object to blink the LED and debounce the switch is no longer needed, so we can delete it. There is no switch press detected, so you don't need to debounce the switch, and the LED isn't blinking, so you don't need the delay between LED on and off. You don't have to delete this, but it will conserve system resources of you do.
After deleting the System Timer Object and initializing the pressDetected flag to false, the state machine transitions to the APP_STATE_LED_OFF_NO_PRESS_DETECT state.
Open the app.c file and add the following code to the application state machine in APP_Tasks (near line #283). Remember to comment out references to the existing APP_STATE_SERVICE_TASKS state as shown below. MHC has generated this example state for you, but you won't use it.
Click image to enlarge.
file: app.c
10
Connect the development board and programmer/debugger to your computer, then select the XC32 compiler version and programmer/debugger for the project
After successfully programming the device, the LED will start blinking. Press Switch 1 (labeled BTN2) on the board to stop the blinking. Press it again to restart the blinking.
Conclusions
This example project demonstrates much more than configuring, monitoring, and controlling PIC32 I/O Port pins. You've also learned the basic program architecture common to all MPLAB Harmony projects.
You may be thinking that this a lot of code to monitor a switch and blink an LED. This is true. An 8-bit device can perform this task for less cost and less code. The assumption is you will want to integrate this code into a larger project that may already implement the Timer System Service (e.g. the Harmony TCP/IP stack). This code will work cooperatively with other Harmony library modules, and it will efficiently share PIC32 resources. It can also be easily reused in other PIC32 projects and frees you from needing to learn details of how the underlying hardware works.