MPLAB® Harmony v2 Ports Project Using chipKIT® Wi-FIRE
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. This I/O Port pin is configured to use its Change Notification feature. This feature generates an interrupt any time a change of state is detected on the pin.
When a button press is detected, a System Timer Object is created. This timer object creates a delay used to debounce the switch and blink the LED. Once a press is confirmed (switch debounced), the LED will start or stop blinking.
When a button press to stop the blinking LED is detected, the LED is shut off. The System Timer Object created when the button press was first detected is then deleted to conserve system resources. The PIC32 will remain in this idle state until another button press is detected, at which point a new System Timer Object will be created.
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. PICkitTM 3) 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, MPLAB XC32 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 Wi-FIRE is the PIC32MZ2048EFG100.
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® Wi-FIRE 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 PIC32MZ2048EFG100 Device list and check the chipKIT WiFIRE (PIC32MZ2048EFG100) 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 PIC32MZ2048EFG100 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 the Ports System Service and I/O Port Change Notification feature.
In the MPLAB Harmony Configurator Options tab, expand the following sub-menus:
Harmony Framework Configuration
System Services
Ports
Check the Use Ports System Service? box.
Check the Use Interrupt for Change Notification? box.
b
Use the Pin Manager to enable the Change Notification feature on the I/O Port pin connected to the switch.
Click the Execute button or click on the Pin Settings tab to view the Pin Manager window.
Pin RA5 (PORTA, bit 5) on the PIC32 is connected to the switch labeled "BTN1" on the chipKIT Wi-FIRE board. Enable the Change Notification Feature on this pin by checking the box shown in the following picture.
Reference the diagram at the top of the page. Note an external pull-down resistor is used to put 0 volts on the pin when the button is not pressed. No internal pull-up or pull-down resistors are needed to keep a valid digital input voltage on the pin while the button is not pressed. Leave these boxes unchecked.
4
Use MHC to enable and configure the Timer System Service
You will use the Timer System Service to generate an interrupt every 50 ms. This 50 ms period will be used to blink the LED and to debounce the switch.
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 #126):
file: app.h
7
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 #196):
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).
8
Modify the interrupt service routine for the I/O Port Change Notice feature.
Open the system_interrupt.c file (found in the Source Files ▶ app ▶ system_config ▶ default folder), and modify the I/O Port Change Notice Interrupt Service Routine (ISR) as shown below (near line #72). The Change Notice ISR will call the APP_SwitchChangeNoticed() callback function every time a switch press is detected.
file: system_interrupt.c
9
Create the callback function used by the Timer Driver (called by Timer ISR).
The Timer System Service you created in a previous step uses a Timer Driver (is a client to the Timer Driver) to keep track of time. When the period of time you specify has elapsed (50 ms in this case), the interrupt service routine associated with this Timer Driver will call this callback function.
This callback function performs two tasks:
If a press is detected (I/O Port Change Notice feature), it will debounce the switch.
Read the value on the I/O Port pin.
If the correct voltage corresponding to a pressed 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 has been confirmed (appData.switchHasBeenPressed = true).
If the state machine is in a blinking state, the LED will be turned on and shut off every 50 ms.
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).
Open the app.c file (found in the Source Files ▶ app ▶ folder), and create the Timer Driver callback function as shown below (near line #98):
file: app.c
10
Create the callback function called by the I/O Port Change Notice ISR.
The ISR for the I/O Port Change Notice feature will call the following callback function every time a change of state (high to low, or low to high) occurs on the pin.
This callback function performs three tasks:
Read the I/O Port to clear the mismatch condition between the new state and the old state.
Clear the I/O Port Change Notice interrupt flag to clear the interrupt condition.
Test for a switch press transition (and ignore the switch release transition) and set the appData.changeNoticed flag if true.
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).
In the app.c file, create the following callback function as shown below (near line #159):
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.switchHasBeenPressed to true, and transitions to the APP_STATE_TIMER_OBJECT_CREATE state. This places the application state machine into a "blinking" state, causing the blinking LED to start blinking as soon as the device comes out of reset.
APP_STATE_TIMER_OBJECT_CREATE
This state uses the Timer System Service to create 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_TimerCallBack()) 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_DEBOUNCE_START.
APP_STATE_DEBOUNCE_START
This state waits for a switch press to be confirmed (waits for the switch debounce to complete). This is happens when appData.switchHasBeenPressed is set to true. When the press is confirmed, it transitions to APP_STATE_LED_BLINKING.
APP_STATE_LED_BLINKING
This state causes the LED to blink (see the System Timer callback function APP_TimerCallBack()). While it is blinking, it monitors the appData.changeNoticed flag to determine if a press has been detected. If it has, it transitions to the next state (APP_STATE_DEBOUNCE_STOP) to wait for the press to be confirmed.
APP_STATE_DEBOUNCE_STOP
This state keeps the LED blinking until a switch press is confirmed. Once a press is confirmed, it will shut the LED off, delete the System Timer object created in APP_STATE_TIMER_OBJECT_CREATE, and transition to the APP_STATE_IDLE state.
The System Timer object is deleted because you don't need to keep track of time anymore. 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.
APP_STATE_IDLE
This state waits for a button press to be detected. When this happens, it transitions to the APP_STATE_TIMER_OBJECT_CREATE state.
Open the app.c file and add the following code to the application state machine in APP_Tasks (near line #235). Remember to comment out references to the existing APP_STATE_SERVICE_TASKS and default states as shown below. MHC has generated this example code for you, but you won't use it.
Click image to enlarge.
file: app.c
13
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 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.