Purpose:
After completing this lab, you will have an understanding of the fundamental elements, layout, and execution model of an MPLAB® Harmony project. You will also learn how to add features and functionality to your MPLAB Harmony project by using the MPLAB Harmony Configurator (MHC).
Overview:
In this lab, you will create a simple MPLAB Harmony project from scratch. You will use the MHC to configure the codec on the PIC32 Multimedia Expansion Board II. The application streams an audio tone (stored in the form of a lookup table in memory) over the I²S interface which gets played on the audio codec. The lab demonstrates basic system initialization and polled state machine design.
APP_TONE_LOOKUP_TABLE_Tasks() |
Lab Source Files and Solutions:
If you haven't already downloaded all source files for the SD card audio player labs:
Download the lab source files and solutions >
This project has been verified to work with the following versions of software tools:
MPLAB X IDE v5.25, MPLAB XC32 Compiler v2.30, MPLAB Harmony MHC v3.3.2, DEV_PACKS v3.5.0, CORE v3.5.0, CSP v3.5.0, BSP v3.5.0, and AUDIO v3.4.0
As the tools are regularly updated, there may be occasional issues while using newer versions. If that is the case, we recommend using the same version as specified in the project.
The archived versions of our tools can be found below:
MPLAB Harmony
MPLAB X IDE and XC32 Compiler
Note: that multiple versions of all these tools can co-exist on the same computer.
Procedure:
All steps must be completed before you will be ready to build, download, and run the application.
Part 1: Create a Project and Configure the PIC32MZ
Part 2: Add Application Code
Step 1: Create an MPLAB Harmony Project in MPLAB X IDE
If you haven't already done this, create a folder under the Harmony installation to place this series of labs.
Navigate to the <Any directory of your choice>/apps folder and create the following folder structure: training/solutions/audio_player. The audio_player folder contains the source files and solutions for all the labs in this exercise.
Download all solution ZIP files using below links and extract all the ZIP files to the training/solutions/audio_player folder. A description of the files and folders found in these ZIP files can be found here.
Navigate to the <Any directory of your choice>/apps/training/solutions folder and create these new folders dev/audio_player. You will develop all your labs under this folder. MPLAB X IDE will create a sub-folder named audio_player_lab1 under the dev/audio_player folder.
Start MPLAB X IDE and create a new project by selecting File > New Project.
In the Categories pane of the New Project dialog, select Microchip Embedded.
In the Projects pane, select 32-bit MPLAB Harmony 3 Project and then click Next >.
Specify the following in the New Project dialog screens:
- Project Location: <Any directory of your choice> indicates the path to the root folder of the new project. All project files will be placed inside this folder. The project location can be any valid path, for example, C:\microchip\harmony3\apps\training\middleware\dev\audio_player\audio_player_lab1
- Enter Folder Name: "audio_player_lab1"
- Enter Project Name: "audio_player_lab1"
- Configuration Name: default
- Target Device: PIC32MZ2048EFH144
After clicking the Finish button, the project will be created and opened. The MHC tool will launch and you will be prompted to select the packages to include for the current project.
The required packages for this series of labs are displayed above. Click the Launch button to continue.
If you close the MHC window, you can re-open it again by clicking on Tools > Embedded > MPLAB Harmony 3 Configurator.
Step 2: Using MHC, Select the Board Support Package
Click on the Project Graph tab to view the Harmony 3 configuration display.
Select PIC32MZ EF Starter Kit BSP from the Available Components window.
If a BSP exists for your development board, you will want to use it. Choosing a BSP lets the MHC know about the hardware you will use for the project. With this knowledge, the MHC can automatically control the following settings for you:
- PIC32 I/O Port pin connections to LEDs and switches
In addition to configuring hardware options for you, the BSP comes with a small group of library functions that allow you to easily interface with LEDs, switches, and other board-specific hardware. In this lab, you will observe the selections the BSP makes for you. This will show you how to make these selections manually in case a BSP does not exist for the board you want to use.
Step 3: Using MHC, Verify Configuration Bits are Correct
Click on the System block in the Project Graph window to view the System Device & Project Configuration options.
Expand the Device & Project Configuration and PIC32MZ2048EFH144 Device Configuration selection tree to view the PIC32 core configuration selections.
The BSP you selected has properly configured these selections for you. This step shows you how to make changes to these selections if needed.
- DEVCFG3 and DEVCFG2: No change required.
- DEVCFG1: Verify Watchdog Timer Enable (FWDTEN) is OFF.
- DEVCFG0: Verify Debugger Communication Channel (ICESEL) is set to ICS_PGx2.
In case you are wondering where these cryptic selection names come from, they correspond to the PIC32 core configuration registers and bit names.
Also, be sure to set the Use Cache Maintenance block under MIPS Configuration > CACHE.
The above configuration is enabled to generate the cache maintenance API. The cache maintenance APIs are used in this application to address the cache coherency issues observed in transferring the data using DMA.
In the same system configuration window, expand the DMA (DMAC) tree options. Enable Channel 0 (for SPI1_TX) and Channel 1 (for SPI_RX).
DMA channels need to be configured for the audio I²S component driver's use. DMA Channel 0 is used to transmit and DMA Channel 1 is used to receive.
Step 4: Using MHC, Verify and Change Oscillator Settings
Select the Clock Diagram tab to display the Clock Configurator window.
You can open the MHC Clock Configurator window by clicking on MHC > Tools > Clock Configuration.
- Verify the BSP has correctly configured the following clock parameters for you:
- POSCMOD set to EC.
- FNOSC set to SPLL.
- FPLLIDIV set to DIV_2.
- FPLLMULT set to MUL_33.
- FPLLODIV set to DIV_2.
- FPLLRNG set to 8-16 Mhz.
Experiment with other clock settings. Did you notice how some selections produce red values? These indicate a bad clock configuration. If you hover over them, a pop-up window will explain the problem.
The PIC32 is connected to a 24 MHz external clock input. You are not using the internal PIC32 oscillator.
When you change the configured clocks away from the default values on the graphical interface, the corresponding selections in the Options tab highlight these changes with a light green background. Any dependency changes made by the system will be highlighted with a light purple background. All selections made under the Clock Diagram tab are reflected under the Options tab. The reverse is also true. You can configure the clocks using the tree selections, but it is much easier to do that graphically.
For custom boards without a BSP, you can use the Phase-Locked Loop's (PLL’s) Auto Calculate feature to determine and set the PLL to multiply and divide values (FPLLIDIV, FPLLMULT, and FPLLODIV). You can see how this works by going back to the Clock Configurator window (Clock Diagram tab).
Change the PIC32 clock frequency to 198 MHz.
This development board can run at a maximum frequency of 200 MHz (selected by default by the BSP). You are using the audio codec on the board, so you need to configure the system frequency to 198 MHz. This change will be explained when you configure the reference clock to provide the MCKI to the audio codec.
- In the MHC Clock Diagram tab, find the System PLL block and select Auto Calculate.
- Change the Desired System Frequency from 200 MHz to 198 MHz.
- Select Apply.
Verify the output to the PLL is now set to 198 MHz.
When you click on a block in the MHC Project Graph tab, the Configuration Options window will show various options you can choose. You can reference information about the device’s configuration settings in the compiler’s user guide and in the device’s datasheet. If your hardware and debugger connections are correct and you are unable to program, debug, or run code on the device, it is very likely that one of these key device configuration settings is incorrect. Before continuing, you must ensure that these settings are correct.
Step 5: With MHC, Verify I/O Pins Using the Graphical Pin Manager
Open the Graphical Pin Manager by clicking on the Pin Settings tab and select to order by Ports.
You can open the MHC Pin Settings and other pin windows by clicking on MHC > Tools > Pin Configuration.
Some of the LED and SWITCH pins have already been defined by the BSP. However, you will need to define some additional pins required by this lab. It is important to name the pins exactly as they are listed in the following table. Many of the drivers are referencing these pins using a specific name. The following table is a list of the pins required by all the labs in this series (in port order).
First, define the pin function since this will reset the name field of the pin.
You can also display the pin configuration by selecting the Pin Diagram tab. This gives a quick view of which pins are being used by the device.
Step 6: Using MHC, Configure the Audio Codec AK4953, I²C Driver, and I²S Driver
Select the MHC Project Graph tab. Remember, if you ever lose the MHC Tool, you can find it here: Tools > Embedded > MPLAB Harmony 3 Configurator.
Add a Codec Driver into your project from the Available Components window.
Expand the tree, Audio > Drivers > Codec and select the AK4953 driver.
If you can select an AK4953 driver, skip to the next step.
If there is no AK4953 driver selection, you are probably using an MHC audio version before this support was added (audio 3.4.0 or before). You can add the driver manually by copying the following files from your downloaded zip file contained in the audio_player/audio folder .
Copy audio_player/audio/driver/codec/AK4953 to <Harmony install path>/audio/driver/codec/.
Copy audio_player/audio/templates/ak4953 to <Harmony install path>/audio/templates/.
Modify the file <Harmony install path>/audio/driver/config/module.py to add the entry for the AK4953 driver.
Restart MHC.
Configure the AK4953 driver component.
The AK4953 component block will be displayed in the Project Graph window as seen in the image below.
You can move component blocks around in the Project Graph by clicking on them and dragging them around.
Highlight the component block by clicking on it. The available configuration setting will display in the Configuration Options window. For this project, keep the default settings.
Attach an I²C driver to the AK4953 component block.
Right click on the yellow diamond next to DRV_I2C to bring up a list of Satisfiers that can be used to attach to this component. Select the I²C driver component by clicking on it.
At this point, you will be asked to auto activate some components required by the system. Select Yes for the core component and No for the FreeRTOS component.
Don't worry if you make a mistake. You can delete components that you inadvertently add. Click on the component in the Project Graph and then click on the red X. You can also add items from the Available Components window, such as the Core component.
Your Project Graph should now resemble the screen shown below.
Configure the Core options by clicking on the Core component block. The will bring up the Core option selections in the Configuration Options window. Ensure that the blocks for Enable System Ports and Enable System DMA are checked.
Attach an I²C peripheral (PLIB) to your I²C driver.
Right click on the diamond for the I2C Instance 0. From the Satisfiers list, select I2C2. This matches the hardware I²C peripheral that is routed to the AK4953 controller on the MEB-II Expansion Card.
Your Project Graph should now resemble the screen shown below.
Click on the I2C2 peripheral to display the Configuration Options available for this component. Check the option to "Ignore NACK from Slave". This option is required because of the way the AK4953 controller has implemented the I²C protocol.
Attach an I²S driver to the AK4953 component block.
Similar to the I²C, right click on the yellow diamond next to DRV_I2S to bring up a list of Satisfiers that can be used to attach to this component. Select the I²S driver component by clicking on it. The resulting screen is shown.
Attach an I²S peripheral (PLIB) to your I²S driver.
Right click on the diamond for the I2S Instance 0. From the Satisfiers list, select I2S1. This matches the hardware I²S peripheral that is routed to the AK4953 controller on the MEB-II Expansion Card. The resulting screen is shown.
Click on the I2S1 peripheral to display the Configuration Options available for this component. Change the Frame Select Pin to F12 (which is used by the MEB-II hardware).
Add the Time system service component.
Expand the Available Components window for Harmony > System Services and select the TIME component.
Your Project Graph should now resemble the screen shown below.
Attach the CORE TIMER to the Time system service.
Right click on the TMR diamond in the Time system service block. Select CORE TIMER from the Satisfiers list.
Your Project Graph should now resemble the screen shown below.
Save the MHC configuration by clicking the save button.
Step 7: Generate Harmony Code and Build Project
Expand the source file folders in the Projects pane. Notice how there are no source files at all, just an empty project with the correct Harmony structure.
Click on the Generate Code button as shown in the following figure. Notice the Merging Strategy option.
Let’s examine what was done after generating code:
The app folder contains files related to your specific application. In the following steps, you will add your own code to the existing app.c and app.h files You will also add other application-specific source files.
The framework folder under the app folder contains customized Harmony Framework files. These files have been generated by the MHC in response to your specific MHC selections.
Also, note the config folder under the Source Files folder contains standard Harmony Framework files that have been added to your project by the MHC (based on your MHC selections). To be clear, unlike the framework files found under the app folder, these files have not been modified by the MHC. They are some of the standard Harmony Framework files included in the Harmony Framework download.
Check for Harmony 3 issues in previously released versions.
In previously released versions of the Harmony 3 audio code (audio 3.4.0 and before), there was an issue with the I²S driver that needs to be resolved in the source file drv_i2s.c. This only needs to be done if you are using a PIC32 type processor. The directory structure below shows the location of this file which gets generated by MHC.
In the source file drv_i2s.c make sure the buffer size is not getting divided down into a word count. Search for all "/= 2" occurrences and comment them out (refer to code below). This occurs five different times in the following functions; _DRV_I2S_BufferQueueTask (occurs twice), DRV_I2S_WriteBufferAdd, DRV_I2S_WriteReadBufferAdd, and DRV_I2S_ReadBufferAdd.
If you do need to modify these lines, the next time you generate code, you will see the following merge screens displayed. Just press the Close button.
Save all files and build the code. To do this, click on the
Clean and Build icon
and verify the project builds successfully.
At this point, you should be able to debug and step through the application. Effectively, you have a running MPLAB Harmony system. However, it is not yet ready to do anything. Next, you will develop your application state machine logic and make sure the system does what you want it to do. You’re ready to start implementing the application now.
Step 8: Include Application-specific Source Files and Add Required Code
Copy source files:
app_tone_lookup_table.c
app_tone_lookup_table.h
from this folder:
apps/training/solutions/audio_player/audio_player_lab1/dev_files
to this one:
apps/training/solutions/dev/audio_player/audio_player_lab1/firmware/src
Add the copied source files to your project.
- Add app_tone_lookup_table.c to Source Files/app by right clicking and selecting Add Existing Item…
Add app_tone_lookup_table.h to Header Files/app by right clicking and selecting Add Existing Item…
Open the app.c file (in the MPLAB X IDE Projects pane under the Source Files > app folder) and add prototype routines as shown below.
Add code to the APP_Initialize function as shown below.
Add code to the APP_Tasks function as shown below.
Save the file before closing.
Step 9: Review the Application Code
C LANGUAGE REFRESHER: enumerated types and structures
In case you need it, here is a refresher on enum and struct types.
Application File: app_tone_lookup_table.h
Open file app_tone_lookup_table.h. This file defines application states, data, and APIs.
Application states corresponding to the state machine, described in the "Overview" section above, are shown in the following image:
Observe the application data structure shown in the following image. Notice the variable state. The variable codec is for the data type corresponding to the AK4953 codec.
Observe the CODEC data structure in the following image.
- handle refers to the instance of the opened AK4953 codec driver.
- Buffered Harmony driver APIs (e.g., DRV_I2S_BufferAddWrite) returns a handle for each data buffer submitted for processing (transmission/reception). writeBufHandle holds the buffer handle for the audio data buffers submitted for transmission using the codec API DRV_CODEC_BufferAddWrite.
- The application can register an event handler to notify when the submitted transmission/reception request is completed. bufferHandler holds the address of the function which is called when the audio data buffer has been transferred by the codec driver.
- context holds an application-specific value passed to the driver.
- txbufferObject holds the address of the audio data that needs to be transferred to the codec. In this example, it will hold the address of a sine tone lookup table.
- bufferSize holds the size of the audio data buffer.
Application APIs for initialization, task state machine, and buffer completion events are declared.
Application File: app_tone_lookup_table.c
Open the app_tone_lookup_table.c file. This file defines the tone lookup table and implements the APIs.
The implementation of function APP_TONE_LOOKUP_TABLE_Initialize sets up the default state of tone lookup table task and initializes the variables for the codec driver.
The APP_TONE_LOOKUP_TABLE_Tasks function implements the task’s state machine as shown in the figure in section Overview above. It starts in the APP_TONE_LOOKUP_TABLE_STATE_CODEC_OPEN state and remains in it until it opens the codec driver and gets a valid driver handle.
In state APP_TONE_LOOKUP_TABLE_STATE_CODEC_ADD_BUFFER, the application submits audio data buffers to the driver queue and enters a waiting state (APP_TONE_LOOKUP_TABLE_STATE_CODEC_WAIT_FOR_BUFFER_COMPLETE) for the last submitted buffer to complete. The number of buffers queued is equal to queue size - 1 (i.e., 2 buffers).
The DMA transfers the last buffer and the codec calls the event handler when the buffer transmission is completed. In the event handler APP_TONE_LOOKUP_TABLE_BufferEventHandler, the state of the task is changed from waiting to complete.
A new buffer is submitted from the state APP_TONE_LOOKUP_TABLE_STATE_CODEC_BUFFER_COMPLETE and the state machine goes to the waiting state again.
The cycle of waiting / complete state continues.
Step 10: Debug Your New Application
Congratulations! I assure you, the hard part is over! You can now build, program, and debug
your first application!
Before you start the debugger, set a breakpoint in the application file in app_tone_lookup_table.c. Through this breakpoint, you can observe that the tone lookup table task is successfully able to open the codec driver.
Debug your first application. Click the
Debug Main Project icon.
Single-step (by pressing the F7 key) through the application state machine to see how each state is executed.
Put a breakpoint in the buffer event handler. Hitting the breakpoint in the event handler indicates that the last submitted buffer is transferred to the codec.
Remove all breakpoints, press the F5 key and allow the application to run.
Connect a headphone to the HP Out connector on the Multimedia Expansion Board II and you should hear a tone.
You are now an MPLAB Harmony developer!
Feel free to debug and step through the code to see how it works. As you continue stepping through the project, you will eventually arrive back at the super loop in the main function. Fundamentally, this is how polled state machines execute within an MPLAB Harmony system.
Time permitting: explore the audio_player_lab1 project files and folders. Observe that the project consists of several “logical” folders within MPLAB X IDE and several physical folders on the disk. This organization is used consistently by MPLAB Harmony applications to keep the files well organized. MPLAB X IDE separates header (.h) files from source (.c) files, so the logical folder structure mirrors (with some small differences) the physical folder structure on the disk under both the header files and source files top-level logical folders. In most cases, the folders on the disk correspond directly to the logical folders in MPLAB X IDE, but the header files and source files are not separated on the disk as they are in the MPLAB X IDE logical folder tree. Also, the app logical folder corresponds to the src folder on the disk.
The application’s src folder contains the main.c file as well as the app.c and app.h files along with other application specific files like app_tone_lookup_table.c and app_tone_lookup_table.h that implement the application (by convention, main.c is identical for all MPLAB Harmony applications). The config folder normally holds one or more configuration-specific folders (config/default in this case) that each contain a complete set of configuration files for an MPLAB Harmony application.
Results
You should be able to hear a sine tone output through the headphone jack on the Multimedia Expansion Board II. If you did not configure the codec driver, I²S driver or REFCLOCK properly, you may not hear the audio at all or may hear distorted audio coming out with clicks and pops in the stream.
Analysis
In this lab, you have successfully played a sine tone on the PIC32 microcontroller and heard the audio through the headphone on the development board. The sine tone produced is 16-bits, at a 48000 sampling rate. The tone as such was produced statically and stored in the form of a lookup table in an array. The MHC was used to configure the hardware modules. The application was developed in a state-based implementation. In the application, audio buffer management was done by using the buffer queuing support provided by the codec driver.
Conclusions
In this lab, you have successfully developed a full-fledged MPLAB Harmony Application. This gives you a fair idea of how MPLAB Harmony helps application development. If you need to add audio support to any of your existing applications, this lab can be used as a reference. This can also be a starting point for your applications which are audio intensive.