Purpose
After completing this lab, you will have an understanding of configuring and adding multiple modules (SD card driver, Serial Peripheral Interface (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 to 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. The audio_player_lab2 application demonstrates the configuration and integration of the additional modules to audio_player_lab1 using the 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() |
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.
Lab Source Files and Solutions:
If you haven't already, 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, and
- MPLAB Harmony v1.08.
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:
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 that 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, we suggest closing any open project from the previous lab. This will prevent confusion since you will be opening the project with the same name as the 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 the Also Rename Project Folder option is selected.
MPLAB X IDE renames the project. It closes the old project and opens the renamed project.
Verify that 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 the 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 a 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 Serial Peripheral Interface (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 General Purpose Input/Output (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 a 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: 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 the 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 screenshot 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 configures 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 as 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 screenshot 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 superset 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 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 File Allocation Table (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 the MHC. If the 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 screenshots will guide you on which changes need to be merged (i.e., accepted).
Click the arrow (highlighted in a 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 the 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 the 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.
The 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.
The MHC also added the fs and tmr folders under the Source Files/framework/system folder. The 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.
The 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.
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 with 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 the 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 Direct Memory Access (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 a 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 breakpoints 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 with 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-bits, 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 the 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.