Purpose:
After completing this lab, you will have an understanding of configuring and adding multiple modules (SD card driver, SPI driver and Files System Service) using the MPLAB® Harmony Configurator (MHC). You will also learn how to integrate these modules into the MPLAB Harmony project. This lab should really start to show you the power of Harmony!
Overview:
This lab adds onto the previous one. The audio_player_lab2 application reads an audio text file from the PIC32 Multimedia Expansion Board II SD card, and streams it over the PIC32 I2S interface to the audio CODEC. The audio file is saved as a .txt file with comma separated left and right channel audio data. audio_player_lab2 demonstrates the configuration and integration of the additional modules to audio_player_lab1 using MHC, thereby extending its functionality.
The naming of functions and variables used in audio_player_lab1 has been changed from APP_TONE_LOOKUP_TABLE_ to APP_TONE_TEXTFILE_SDCARD_. Otherwise the basic application flow remains the same.
| APP_TONE_TEXTFILE_SDCARD_Tasks() |
The APP_TONE_TEXTFILE_SDCARD_Tasks() adds four new states to the audio_player_lab1 state machine. These states are related to mounting the file system on the SD card, opening and reading the audio text file, and parsing the text file before the audio data is passed to the audio CODEC.
Click image to enlarge.
Click image to enlarge.
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 v3.26, MPLAB XC32 Compiler v1.40, MPLAB Harmony v1.08
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.
Procedure:
This lab builds off the work you performed in the previous lab. If you did not perform SD card Audio Player Lab1, please start Lab2 using the Lab1 solution project (found under the firmware folder). Verify it works as expected before continuing with this lab.
All steps must be completed before you will be ready to build, download, and run the application.
Lab Index
Step 1: Copy source files and rename project for Lab2
Create a new folder audio_player_lab2 under
apps/training/middleware/dev/audio_player.
At this point, it is suggested to close any open project from previous Lab.
This will avoid confusion since you will be opening the project with same name as previous Lab before renaming it for this Lab.
Copy the firmware folder from
apps/training/middleware/dev/audio_player/audio_player_lab1
to the newly created folder (audio_player_lab2).
Rename the project from "audio_player_lab1" to "audio_player_lab2", because by the end of this session the lab will have "audio_player_lab2" functionality. Open "audio_player_lab1".
In the MPLAB® X IDE "Projects" pane, right click on "audio_player_lab1" and select "Rename…"
In the popup window, rename the lab from "audio_player_lab1" to "audio_player_lab2". Make sure that Also Rename Project Folder option is selected.
MPLAB X IDE renames the project. It closes the old project and opens the renamed project.
Verify the project builds properly after renaming. Click the "Clean and Build" icon:

In the MPLAB® X IDE "Projects" pane, right click on audio_player_lab2 and select "Set as Main Project"
Open MHC: In the MPLAB X IDE click on: Tools > Embedded > MPLAB Harmony Configurator.
Step 2: With MHC, Configure the SD card driver, SPI driver and File System
In the MHC "Options" tab, expand the Harmony Framework Configuration > Drivers > SD Card selection tree.
Check the "Use SD Card Driver?" box.
The "Dynamic" "Driver Implementation" is selected by default and greyed out. The SD card driver does not support static implementation yet.
Open one client of the SD card driver. Keep the "Number of SD Card Driver Clients" value at 1.
Use index 0 to identify the driver instance. Keep the "SD Card Driver Index" value at "DRV_SDCARD_INDEX_0".
Retain the "Maximum Driver Indeces (limit 2)" to 1, as you will need only one instance of SD Card driver.
"SD Card Data Queue Size" defines the number of read/write requests that can be queued without having to wait for previous request to complete. Retain the default value of 10.
Select "CLK_BUS_PERIPHERAL_2" as a clock source for "Clock To Use?" because "CLK_BUS_PERIPHERAL_2" is a clock source for the SPI module. The SPI module is used by the SD card driver as the communication interface module.
"SD Card Speed(Hz)", defines the speed at which the SD card is going to operate. This should be less than the maximum SPI frequency and should be supported by the SD card used. You will retain the default value of 20 MHz.
Micro SD cards do not have a write protection line. You can uncheck the "Enable Write Protect Check?" box. If required, a GPIO may be used to set up write protection and the SD card driver can be notified of this GPIO by selecting (checking) this box, and specifying the appropriate "Write Protect Port" and "Write Protect Port Bit" under the "Enable Write Protect Check?" option.
For the SD card operating in SPI mode, the DATA3/CD line of the SD card is used as chip select line, and the same is connected to the PIC32's port pin RB14. Select PORT_CHANNEL_B as the "Chip Select Port" and "PORTS_BIT_POS_14" as the "Chip Select Port Bit".
Note that the SD card initialization routine will set the appropriate direction (output) for the chip select line and hence overwrite any settings for this pin in the Pin Settings tab in MHC.
Retain the "SPI Driver Instance to use for SD Card Driver" to 0. This informs the SD card driver about the SPI instance to be used for communication with the SD card.
Keep the "Register With File System?" option checked. This allows the SD card driver to register its services with the File System.
Observe the following screen shot of the MHC configuration for the SD card driver:
Configure the SPI interface driver, because in the SD card driver configurations, you specified that SPI instance 0 should be used by the SD card driver.
Expand the "Harmony Framework Configuration > Drivers > SPI" selection tree.
Check the "Use SPI Driver?" box.
Select "DYNAMIC" for the "Driver Implementation".
Next, check (select) the following boxes:
"Use Interrupt Mode?"
"Use Master Mode?"
"Use Enhanced Buffer (FIFO) Mode?"
"Use 8-bit Mode?"
This will configure the SPI driver to operate in master mode. The interrupt mode will allow the SPI driver state machine to be run from the SPI interrupt. The demo uses the Enhanced Buffer (FIFO) mode supported by the device.
You need only one SPI driver and client instance. Retain the values for "Number of SPI Driver Instances" and "Number of SPI Driver Clients" at 1.
"Number of job elements created per instance" selects the number of SPI requests that can be queued. Retain the default value 10.
Check the "SPI Driver Instance 0" box.
Select the "SPI Module ID" as "SPI_ID_2". This links the SPI hardware peripheral with the SPI driver instance (Peripheral SPI2 with SPI driver instance 0 in this case).
Expand the "Driver Mode" option and verify that the "Interrupt Mode" box is checked.
Change the "TX Interrupt Priority", "RX Interrupt Priority" and "Error Interrupt Priority" to "INT_PRIORITY_LEVEL3". Also, change the "TX Interrupt Sub-priority", "RX Interrupt Sub-priority" and "Error Interrupt Sub-priority" to "INT_SUBPRIORITY_LEVEL3". This will allow the audio codec (I2S) to run at a higher priority than the SD card (SPI).
The SD card driver will act as an SPI master talking to the SD card as an SPI slave. Verify that the "Master" box is checked under "Master/Slave Mode"
Verify the ‘8-bit’ box under "Data Width", and the "Enhanced" box under "Buffer Mode" are checked.
Retain the default selection for "Protocol Type": "DRV_SPI_PROTOCOL_TYPE_STANDARD"
Select "CLK_BUS_PERIPHERAL_2" as clock source for the SPI module under "Clock To Use" because "CLK_BUS_PERIPHERAL_2" is the clock source for the SPI module.
The value for "SPI Clock Rate – Hz" can be left to the default value. This is because when SPI is used with the SD card, the SD card driver sets the SPI clock rate based on the "SD Card Speed(Hz)" (under SD card tree) setting and the "SPI Clock Rate - Hz" value is ignored.
Set the SPI clock phase and polarity under "Clock Mode" to "DRV_SPI_CLOCK_MODE_IDLE_LOW_EDGE_FALL" and "Input Phase" to "SPI_INPUT_SAMPLING_PHASE_AT_END". You are advised to refer to the micro SD card spec for appropriate selection of "Clock Mode" and "Input Phase".
Retain the default values of 10 and 1 for "Max Jobs In Queue" and "Minimum Number Of Job Queue Reserved For Instance" respectively.
Observe the following screen shot of the MHC SPI driver configuration:
The driver level configuration is used to include various driver capabilities. For example, if the user has selected two SPI instances with one of the SPI instances configured for master mode and another configured for slave mode, then both "Use Master Mode?" and "Use Slave Mode?" needs to be selected in the driver level configuration. In other words, the driver level configuration must be a super set of (that is, it must include) all instance level configurations. You are going to use only one instance of SPI and so the driver level configuration and the instance level configuration will have to be the same.
Verify/Set the I/O pins used by the SPI module using the Graphical Pin Manager
Click on MHC's "Pin Diagram" tab. In the MHC Output pane (bottom of MPLAB X IDE window) select the “Pin table” tab.
The SPI2 has a dedicated pin for SCK2 signal. This pin is hardcoded and configured by the SPI driver.
Map SPI2 signals SDI2 and SDO2 to pins RD7 and RG8 respectively. This user's guide contains the MEB II board schematic.
Expand the "Harmony Framework Configuration > System Services > File System" selection tree.
Check the "Use File System Service?" Box
Set the value of "Maximum Simultaneous File Access" to 2. This allows a maximum of 2 files to be opened simultaneously. You need to be able to open the second file before closing the first file. This is needed for changing tracks.
Retain the default values for "Size Of Block" to 512, "Size Of Media Flash Page Buffer" to 2048, "Total Number Of Media" to 1, and "Total Number Of Volumes" to 1. Note that you are using only one media SD card with only one partition. Verify that "Media 0" is checked.
Retain the "File System Types" to 1. Check the "FAT File System" as the file system type.
Observe the following screen shot of the MHC configuration for the File System.
Save the MHC configuration by clicking the save button.
Step 3: 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 the "Generate Code" button as shown in the following figure. Notice the Merging Strategy option added in Harmony v1.08.
Resolve code generation merge conflicts.
When the Generate button is clicked, MHC will modify and generate source files based on the options selected in MHC. If MHC generates code that will change a pre-existing file, it will show you the code it generated, and allow you to confirm if you want to add it to your source code. The following screen shots will guide you on which changes need to be merged (i.e., accepted).
Click the arrow (highlighted in green circle) to copy and merge from the Generated Code to the Current file.
Click the "Next" button (highlighted in blue) to move to the next merge conflict.
Note that the below definition needs to be retained in the Current File.
Let’s examine what was done after MHC generated the code:
The app folder contains files related to your specific application. In the following steps, you will add your application code to the existing app.c and app.h files. You will also add other application specific source files to the project.
The framework folder under the app folder (Source Files/app/system_config/pic32mz_ef_sk_meb2/framework) contains customized Harmony Framework files. These files have been generated by MHC in response to your specific MHC selections.
Also note the Source Files/framework folder contains standard Harmony Framework files that have been added to your project by 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 MHC. They are some of the standard Harmony Framework files included in the Harmony Framework download.
MHC has added three new (with respect to the previous lab) folders to this lab under the Source Files/framework/driver folder: sdcard, spi, and tmr. These folders include source files that implement the Harmony SD card, SPI and Timer Drivers.
MHC also added the fs and tmr folders under the Source Files/framework/system folder. MHC knows the Harmony SD card driver requires the File System Service and Timer System Service libraries, so it added these Harmony libraries to the project for you.
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 4: Include application specific source files and add required code
Copy source files into your project's source files folder:
app_tone_textfile_sdcard.c
app_tone_textfile_sdcard.h
Copy them from this folder:
apps/training/middleware/audio_player/audio_player_lab2/dev_files
to this one:
apps/training/middleware/dev/audio_player/audio_player_lab2/firmware/src
Add the copied source files to your project.
- Add app_tone_textfile_sdcard.c to the Source Files/app folder (in the MPLAB X IDE "Projects" pane) by right clicking and selecting Add Existing Items…
- Add app_tone_textfile_sdcard.h to the Header Files/app folder by right clicking and selecting Add Existing Items…
Remove the application files of "audio_player_lab1":
app_tone_lookup_table.c
app_tone_lookup_table.h
Right click on these file names in the "Projects" pane, and select “Remove From Project”.
Since you are retaining the app.c and app.h files from "audio_player_lab1", you need to change some of the function names to correspond with the newly included app_tone_textfile_sdcard.c file.
Open the file app.c and change the name of this function from
APP_TONE_LOOKUP_TABLE_Initialize() to
APP_TONE_TEXTFILE_SDCARD_Initialize()
in function APP_Initialize as shown below.
Similarly, change the name of this function from
APP_TONE_LOOKUP_TABLE_Tasks() to
APP_TONE_TEXTFILE_SDCARD_Tasks()
in function APP_Tasks as shown below.
Save the file before closing.
Open the file system_config.h and change the name of the macro definition under "Section Middleware & Other Library Configuration" from
APP_TONE_LOOKUP_TABLE_CODEC_WRITE_QUEUE_SIZE to
APP_TONE_TEXTFILE_SDCARD_CODEC_WRITE_QUEUE_SIZE as shown below.
Save the file before closing.
Step 5: Review the application code
Application File: app_tone_textfile_sdcard.h
Open file app_tone_textfile_sdcard.h. This file defines application states, data and APIs.
Application states corresponding to the state machine described in the "Overview" section above are as follows. Note the newly added states are highlighted in the red box.
Application data structure is shown below.
- The variable state and codec are retained from "audio_player_lab1". They hold the state of application and codec related variables respectively.
- "audio_player_lab1" had the audio data saved in a global buffer, whereas "audio_player_lab2" will read ASCII audio text data from a file saved in the SD card. This ASCII data needs to be parsed. The variable textParser holds the ASCII text data to be parsed. (see "APP_TONE_TEXTFILE_AUDIO_DATA_PARSER" below).
- "fileHandle" holds the handle to a file opened by using the File System API call "SYS_FS_FileOpen".
- "fileSize" holds the size of the opened file.
- "currentFilePosition" holds the current file position.
- "buffer" holds the ASCII data read from the tone.txt file. The buffer serves as an input to the audio data parser routine. It converts the comma separated ASCII audio values to binary integer values.
- "nElements" holds the number of ASCII values present in the ‘buffer’ that need to be parsed.
- The codec data structure will remain the same. It is included here for completeness.
Application APIs for initialization, Task state machine and Buffer completion events are declared.
Application File: app_tone_textfile_sdcard.c
Open file app_tone_textfile_sdcard.c. This file contains the application state machine and implements the APIs.
The implementation of function APP_TONE_TEXTFILE_SDCARD_Initialize sets up the default state of APP_TONE_TEXTFILE_SDCARD_Tasks and initializes the variables for the CODEC driver, along with other variables.
The function APP_TONE_TEXTFILE_SDCARD_Tasks implements the task’s state machine as shown in the figure in section ‘Overview’ above.
As in "audio_player_lab1", it starts in APP_TONE_TEXTFILE_SDCARD_STATE_CODEC_OPEN state and remains in it until it opens the CODEC driver and gets a valid driver handle.
The state APP_TONE_TEXTFILE_SDCARD_STATE_CODEC_SET_BUFFER_HANDLER registers a buffer event handler with the CODEC driver.
The state APP_TONE_TEXTFILE_SDCARD_STATE_CARD_MOUNT mounts the FAT file system to the SD card.
After the file system is successfully mounted, the state machine enters APP_TONE_TEXTFILE_SDCARD_STATE_CARD_CURRENT_DRIVE_SET state where it sets the current drive of file system to the specified path and then opens the tone.txt audio file.
In the APP_TONE_TEXTFILE_SDCARD_STATE_READ_FILE_SIZE the size of the opened file (tone.txt) is read.
The state APP_TONE_TEXTFILE_SDCARD_STATE_CARD_READ reads the ASCII audio data contained in the tone.txt file, and passes the read buffer to the APP_TONE_TEXTFILE_SDCARD_Parse_Audio_Text_Data routine which converts it to binary data and saves it in the buffer pointed by the codec variable.
The entire tone.txt file is read and converted in one shot, and the audio data buffer appToneTextFileSdcardToneBuffer is updated.
In state APP_TONE_TEXTFILE_SDCARD_STATE_CODEC_ADD_BUFFER, the application submits audio data buffers to the driver queue and enters into a waiting state (APP_TONE_TEXTFILE_SDCARD_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_TEXTFILE_SDCARD_BufferEventHandler, the state of the task is changed from waiting to complete.
A new buffer is submitted from the state
APP_TONE_TEXTFILE_SDCARD_STATE_CODEC_BUFFER_COMPLETE and the state machine goes to the waiting state again. The cycle of waiting <-> complete state continues.
System Configuration File: system_config.h
This file defines appliation specific configuration macros.
APP_TONE_TEXTFILE_SDCARD_CODEC_WRITE_QUEUE_SIZE has the size of the CODEC driver buffer queue.
#define APP_TONE_TEXTFILE_SDCARD_CODEC_WRITE_QUEUE_SIZE QUEUE_SIZE_TX_IDX0
Step 6: Debug your application
Congratulations! You’re done: you are ready to DEBUG

your second application.
Before you program and run your application, you need to program the micro SD card with the audio text file. Go to the dev_files folder of this lab apps/training/middleware/audio_player/audio_player_lab2/dev_files, and copy the tone.txt file into the micro SD card.
Insert the micro SD card into the micro SD card slot (J8) on the MEB II Board.
Before you start the debugger, set a breakpoint in the application file in app_tone_textfile_sdcard.c. Through this breakpoint you can observe that the APP_TONE_TEXTFILE_SDCARD_Tasks() is successfully able to open the CODEC driver.
Put a breakpoint in the APP_TONE_TEXTFILE_SDCARD_STATE_CARD_MOUNT state. Through this breakpoint you can observe that the file system was successfully mounted on the SD card.
Debug your application! Click the “Debug Main Project” icon

Single step (by pressing key ‘F7’) to observe the flow of the application state machine.
Put breakpoint in the buffer event handler. Hitting this breakpoint in the event handler indicates that the last submitted buffer is transferred to the CODEC.
Remove all break points and press key ‘F5’ 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.
Results
As in audio_player_lab1 you should be able to hear a sine tone output through the headphone jack on the Multimedia Expansion Board II. There could be issues with the audio output if you did not configure the SD card driver or File System Service properly (the audio data is read from the text file stored in the SD card).
Analysis
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-bit, at a 48000 sampling rate. The tone was produced statically and stored in a text file on the SD card mounted on the board. The existing configuration from audio_player_lab1 was enhanced using MHC to configure the SD card driver and File System Service to access the audio text file stored on the SD card. The application state machine was enhanced to add new steps to read audio data from the text file.
Conclusions
In this lab you have extended the audio_player_lab1 to add another level of complexity. Now you should be in a position to appreciate how easy it was to add new modules (driver/system service) to an existing application. This lab can also be used as a reference for dealing with File Systems and SD card memory management.