Getting Started with USB on SAM MCUs Using MPLAB® Harmony v3: Step 5

Add Application Code to the Project

The application is already developed and is available in the following files:

  • common.h
  • app_eeprom.h
  • app_eeprom.c
  • app_sensor.h
  • app_sensor.c
  • app_usb.h
  • app_usb.c
  • main.c

They are available under <your unzipped folder path>\getting_started_drivers_middleware\dev_files

The application files app_eeprom.c, app_sensor.c, and app_usb.c contain the application logic. They also contain placeholders that you will populate with the necessary code.

1

Go to the <your unzipped folder path>\getting_started_drivers_middleware\dev_files folder and copy the pre-developed files:

  • common.h
  • app_eeprom.h
  • app_eeprom.c
  • app_sensor.h
  • app_sensor.c
  • app_usb.h
  • app_usb.c
  • main.c
copy_dev_files.png
Figure 1: Copy Files

Paste and replace (overwrite) the files of your project at <your harmony 3 project folder path>\getting_started_drivers_middleware\firmware\src with the copied files.

paste_replace_files.png
Figure 2: Paste and Replace Files

2

Add the application header file common.h to your project.

add_common_1.png
Figure 3: Add Existing Item…
add_common_2.png
Figure 4: Select common.h
add_common_3.png
Figure 5: Added common.h

3

For a Harmony v3 application, MPLAB® Code Configurator (MCC) generates the application template files app_eeprom.h, app_eeprom.c, app_sensor.h, app_sensor.c, app_usb.h, app_usb.c, main.c. The main.c file calls the SYS_Tasks() routine which runs the Sensor, EEPROM, and USB application tasks. It also calls the requisite Driver, System Service, and Middleware tasks if they're added to the project using MCC.

main_sys_tasks.png
Figure 6: SYS_Tasks Routine

4

The app_sensor.h, app_eeprom.h, and app_usb.h files define the states of the application. Try to relate the states with the state diagrams shown at the beginning of this lab.

app_sensor_states.png
Figure 7: Sensor App States
app_eeprom_states.png
Figure 8: EEPROM App States
app_usb_states.png
Figure 9: USB App States

5

The app_sensor.h, app_eeprom.h, and app_usb.h files also define the application data structures APP_SENSOR_DATA, APP_EEPROM_DATA, and APP_USB_DATA.

app_sensor_data.png
Figure 10: Sensor App Data
app_eeprom_data.png
Figure 11: EEPROM App Data
app_usb_data.png
Figure 12: USB App Data

6

The functions APP_SENSOR_Tasks(), APP_EEPROM_Tasks(), and APP_USB_Tasks() in the files app_sensor.h, app_eeprom.h, and app_usb.h implement the application state machine.

7

The Sensor Task in app_sensor.c and the EEPROM Task in app_eeprom.c acts as the two Clients to the I²C Driver Instance 0.

i2c_client_overview.png
Figure 13: I²C Driver Clients

8

Open app_sensor.c and add the application code as shown in the following steps.

a

Open the I²C Driver Instance 0 (which is associated with TWIHS0 Peripheral Library). The call to DRV_I2C_Open() Application Programming Interface (API) will associate the Sensor Client with the I²C Driver Instance 0. The returned handle will be used by the Sensor Task in all subsequent calls to the driver.

Line numbers are provided beside each code snippet. If you don't see line numbers in MPLAB X IDE, enable them by navigating to View > Show Line Numbers from the menu bar.

You can use Ctrl + G to jump to a line number on the editor.

app_sensor_sub_a.png

b

Set the transfer parameters for the sensor client after a valid handle to the driver is obtained. The transfer parameter sets the I²C clock speed to 100 kHz for this client.

app_sensor_sub_b.png

c

Register an event handler (callback) with the I²C driver for the sensor client. The event handler is called by the I²C driver when any request submitted by the sensor application client is completed.

app_sensor_sub_c.png

d

Register a periodic callback with the TIME System Service for every 1000 milliseconds.

app_sensor_sub_d.png

e

Set a flag in the periodic timer event handler. The sensor task will read the temperature when the flag is set and also toggle the I/O1 Xplained Pro LED.

app_sensor_sub_e.png

f

When the periodic timer expires, submit an I²C transfer request to read the temperature sensor value using the I²C driver write-then-read API.

app_sensor_sub_f.png

g

The I²C driver calls the sensor I²C event handler APP_SENSOR_I2CEventHandler() when a submitted request is complete and sets a flag indicating the read is complete.

app_sensor_sub_g.png

h

The COMMON_APP_SENSOR_GetTemperature() function declared in common.h and defined in app_sensor.c provides a common interface between tasks and is used in app_usb.c to fetch the latest temperature value. Return the latest temperature value when this function is called.

app_sensor_sub_h.png

i

Once the temperature is read, notify the EEPROM Task to log the current temperature value to EEPROM.

app_sensor_sub_i.png

9

Open app_eeprom.c and add the application code as shown in the following steps.

a

Associate the second I²C client, with the I²C Driver Instance 0. This is done by opening the I²C Driver Instance 0 again. The call to DRV_I2C_Open() API will now associate the EEPROM Client with the I²C Driver Instance 0. The returned handle will then be used by the EEPROM Task in all subsequent calls to the driver.

app_eeprom_sub_a.png

b

Like the Sensor Client, set up the transfer parameters for the EEPROM Client after a valid handle to the driver is obtained. The transfer parameters set the I²C clock speed to 400 kHz for this client.

app_eeprom_sub_b.png
  • The call to DRV_I2C_TransferSetup() overrides the baud rate set in the I²C driver configuration using MCC.
  • I²C was configured to run at 400 kHz using MCC. While in the application, the Sensor Task has reconfigured it to run at 100 kHz and the EEPROM Task configured it to run at 400 kHz. This illustrates how the Harmony I²C driver handles the peripheral's configuration depending on the client accessing the peripheral.

c

Like the Sensor Client, register an event handler (callback) with the I²C driver for the EEPROM Client. The event handler would be called by the I²C driver when any request submitted by the EEPROM application client is completed.

app_eeprom_sub_c.png

d

When the Sensor Task notification occurs, submit an I²C transfer request to write the temperature sensor value using the I²C driver write API.

app_eeprom_sub_d.png

e

The COMMON_APP_EEPROM_GetTemperature() function declared in common.h and defined in app_eeprom.c provides a common interface between tasks and is used in app_usb.c to fetch the last five temperature values from the EEPROM. When this is called, submit an I²C transfer request to read the last five temperature values from the EEPROM using the I²C driver write-then-read API. Once this completes, store the temperature values in the requisite buffer.

app_eeprom_sub_e.png

f

The I²C driver calls the EEPROM I²C event handler APP_EEPROM_I2CEventHandler() when a submitted request is complete and sets a flag indicating the read is complete.

app_eeprom_sub_f.png

10

Open app_usb.c and add the application code as shown in the following steps.

a

Open the USB device layer and store the handle returned, this handle will be used for all subsequent calls to the device layer.

app_usb_sub_a.png

b

Register a callback with the device layer using the handle returned in the previous step to receive the USB device layer's event notifications.

app_usb_sub_b.png

c

Once the USB device is plugged in and the enumeration is complete, the previously configured callback will be called by the USB device layer. Set a flag to notify the state machine that the USB device is now configured and turn on the SAME70 Xplained board LED to show the same.

app_usb_sub_c.png

The LED on the SAM E70 Xplained Pro is active low, so, clear the pin to turn it on.

d

Since the USB device is now configured, you can now register a separate callback to receive the CDC function driver's events as shown below.

app_usb_sub_d.png

e

Once the USB device is configured, schedule a read using the USB CDC function driver's USB_DEVICE_CDC_Read() API.

app_usb_sub_e.png

f

When data is successfully received by the CDC function driver from the USB host (PC), the APP_USB_USBDeviceCDCEventHandler() is called. Using the USB_DEVICE_CDC_EVENT_READ_COMPLETE event, notify the state machine by setting a flag as shown below.

app_usb_sub_f.png

g

Process the character read from the host, if it's 1, toggle the board LED.

app_usb_sub_g.png

h

Process the character read from the host, if it's 2, show the latest temperature value by using the common interface to the Sensor Task.

app_usb_sub_h.png

i

Process the character read from the host, if it's 3, show the last five temperature values by reading it from the EEPROM using the common interface to the EEPROM Task.

app_usb_sub_i.png

j

Process the character read from the host, if it's 4, show the latest light sensor value by reading the sensor voltage using the AFEC1 Peripheral Library. The output is formatted as a percentage of the light sensor's full-scale output voltage.

app_usb_sub_j.png

k

Once a valid command is processed, schedule a write for the data to be displayed using the USB CDC function driver's USB_DEVICE_CDC_Write API.

app_usb_sub_k.png

l

When data is successfully sent by the CDC function driver to the USB host (PC), the APP_USB_USBDeviceCDCEventHandler() is called. Using the USB_DEVICE_CDC_EVENT_WRITE_COMPLETE event, notify the state machine by setting a flag as shown below.

app_usb_sub_l.png

You are now ready to build the code!



Next Step >

© 2024 Microchip Technology, Inc.
Notice: ARM and Cortex are the registered trademarks of ARM Limited in the EU and other countries.
Information contained on this site regarding device applications and the like is provided only for your convenience and may be superseded by updates. It is your responsibility to ensure that your application meets with your specifications. MICROCHIP MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND WHETHER EXPRESS OR IMPLIED, WRITTEN OR ORAL, STATUTORY OR OTHERWISE, RELATED TO THE INFORMATION, INCLUDING BUT NOT LIMITED TO ITS CONDITION, QUALITY, PERFORMANCE, MERCHANTABILITY OR FITNESS FOR PURPOSE. Microchip disclaims all liability arising from this information and its use. Use of Microchip devices in life support and/or safety applications is entirely at the buyer's risk, and the buyer agrees to defend, indemnify and hold harmless Microchip from any and all damages, claims, suits, or expenses resulting from such use. No licenses are conveyed, implicitly or otherwise, under any Microchip intellectual property rights.