This example shows how to communicate between the AVR DU microcontroller and a host computer using the USB Communication Device Class (CDC). In addition to an application that will work with standard terminal applications, a python script is included showing how to easily interface with the AVR DU over CDC.
- AVR® DU Family Product Page
- USB CDC to USART Bridge using AVR DU Microcontroller
- USB CDC Specification
- MPLAB® X IDE 6.20.0 or newer
- MPLAB® XC8 2.46.0 or newer compiler
- MPLAB® Code Configurator(MCC) v5.5.0 plug-in or newer
- MPLAB Data Visualizer v1.3.1665 or newer
- Python 3.11.0 or newer
The AVR DU Curiosity Nano Development Board has two USB-C® ports. One for programming the device via the on-board debugger and one connected directly to the AVR DU. While programming the device over the AVR DU's port is possible using bootloaders, this example uses the debugger port so both ports needs to be connected to the host computer. After programming, only the AVR DU side needs to continue being connected.
The Curiosity Nano has an Adjustable Target Regulator that regulates voltage to 3.3V by default. Since the USB peripheral in the AVR64DU32 needs to run at 3.3V, it either needs a 3.3V supply connected on the VUSB pin or a 5.0V supply on VDD with the internal USB Voltage Regulator active. With the Curiosity Nano default settings, the VBUS pinheader on the board must be connected with the included jumper to supply 3.3V directly to VUSB.
This section shows how the example is set up in MPLAB using MCC. An overview of the complete MCC setup is shown in the image below:
- Start a new Microchip Embedded Application Project in MPLAB, selecting the AVR DU as your device.
- Open MCC to start setting up the USB Device Stack:
- If the USB library doesn’t show up in Libraries under Device Resources (By default on the left in MPLAB) it needs to be added in the Content Manager menu. The button is in the Device Resources section or under Tools in the menu.
- Add the USB Device Stack library to the project.
- Add the AC0, RTC and VREF drivers to the project.
- Follow the setup below to configure the library and drivers.
The configurator is set so that the AVR DU will identify as a CDC device on the highest level. The toggle switch for adding the Virtual Serial example code is also enabled.
For this example, the Device Descriptors section is left as default. For other applications, information on the product can be added here.
For this example, both a communication and data interface are required.
The communication interface determines how the communication flow between the host and device. The Abstract Control Model (ACM) is used as a subclass but few of the supported commands are needed. Three Functional Descriptors are also required:
- Header - Required for Functional Descriptors
- ACM - Tells the host what commands the device supports (D1 indicates that device supports basic Line Coding and Control Line State commands needed for terminal applications)
- Union - Tells the host the relationship between two or more interfaces
All communication is sent over the data interface for this basic Virtual Serial Port application. The Packet Size field determines how much data can be transmitted in one USB packet. The data sent can be bigger or smaller and the stack will transmit a less amount or split it up in smaller packages.
This example is configured to run on 24 MHz. The minimum oscillator frequency for USB on the AVR DU is 12 MHz.
The application uses a delay function to blink an LED if the USB connection fails. This delay function is dependent on knowing the main clock speed through the F_CPU define. Here, this has been set up as a preprocessed define macro in the project settings.
Alternatively, it could have been added in the main file as #define F_CPU 24000000UL
above the #include <util/delay.h>
line.
To ensure that the USB peripheral only tries to attach to the bus when the Curiosity Nano is connected to the PC, the Analog Comparator will be checked periodically if the voltage is within the acceptable range for VBUS.
In the VREF peripheral, the Voltage Reference is set to 2.048V.
The Analog Comparator must be enabled by toggling Enable under Hardware Settings.
The positive input is set to the USB DETECT pin on the Curiosity Nano which is connected to Positive Pin 4 on the AC by default. The detection threshold is set using the internal reference voltage generator (DACREF) which is selected as the negative input to the AC.
To calculate the DACREF, use the formula from the data sheet:
VDACREF> = (DACREF / 256) * VREF
Due to the voltage divider present on the Curiosity Nano, a threshold of 0.32V is needed for this project. Inputting this value into the Requested Voltage field in MCC can calculate the DACREF value automatically.
Refer to the AVR64DU32 Curiosity Nano User Guide for more information on how the USB DETECT is implemented on the Curiosity Nano.
The RTC Periodic Interrupt Timer (PIT) is used to trigger the voltage detection described above.
The RTC is configured to run on a 1 kHz clock with no prescaler.
The PIT is then set to trigger at every 32 clock cycles of the RTC clock, which gives an update rate of ~31 Hz.
The application is set up to need five stable voltage readings before initiating the USB communication. Considering the previous settings and an environment with no voltage fluctuations, the start-up time is in the 0.16s range.
The on-board LED of the Curiosity Nano is used to indicate if the USB communications has failed. The LED is connected to the PF1 pin and can be selected as an output in the Pin Grid View below.
The pin is given a custom name in the Pins menu, as seen below. This makes the code easier to read with the functions generated using this name.
Since this example uses interrupts both for voltage monitoring and for USART communication, toggle the Global Interrupt Enable button Interrupt Manager.
The included application is set up to echo back any data received over CDC.
The application checks if there is data in the received buffer and adds the data to the transmit buffer as long as the peripheral is ready and the buffer isn't full. The full flow of the main application can be seen in the diagram below.
The USB part of the application is set up in polling mode and therefore needs to handle the USB peripheral inside the main loop. Interrupt mode is also selectable in MCC and it simplifies the application by removing the need for USB handler.
When the device is programmed, it will show up as a Virtual Serial Port on the host. The method varies between operating systems and the most common cases are listed below. As MPLAB Data Visualizer is used in this example, the appropriate serial ports will show up directly in the program.
In Windows, the easiest way to identify the port number is to go to Device Manager>Ports (COM and LPT) to easily identify the port number.. The device shows up as USB Serial Device (COM##), where ## is the number assigned by the host.
Alternatively, the following commands will also list the devices in terminal.
Command Prompt:
reg query HKLM\HARDWARE\DEVICEMAP\SERIALCOMM
PowerShell:
Get-WMIObject Win32_SerialPort | Select-Object Name,DeviceID,Description
Using the terminal, add the command below to generate a list of connected devices.
ls /dev/tty.*
This section assumes that the setup has been followed and that the device is programmed and connected to the host.
Step-by-step guide to open communication:
- Open MPLAB Data Visualizer:
- The Curiosity Nano will show up in the connection pane to the left side of the window
- Send the COM port to the terminal window:
- While hovering over the Curiosity Nano COM port, an option to "Display as text in the terminal" will appear
- Serial connection will now have started
- Write any input in the terminal window and it will echo back when enter is pressed.
Reading the USB CDC Virtual Serial Port data in a terminal isn't always the most useful way to access it. This section will demonstrate how to transmit and receive data using a Python script.
In addition to basic packages included by the standard Python installation, the script also uses pyserial that needs to be installed separately.
pip install pyserial
The included script is quite sparse and is only meant to show the basic functionality. While both Curiosity Nanos USB ports are connected and the device is programmed as described in the previous example, running the script is done using the following command:
python usb_cdc_virtual_serial_port.py
The python prefix depends on the installed Python version and setup.
Running the script will print a status message for trying to open the serial communication:
Opening serial communication...
When communication is established, it will transmit a preset array of values to the AVR DU and print the following:
Transmitting Data:
<data transmitted as hex values>
The script will then attempt to read the echo from the AVR DU using the number of transmitted bytes as a limit on how many bytes to read. It will then print the received bytes in ASCII form:
Received Data:
b'<data received as ASCII characters>'
Python's serial.read()
interprets the returned values as ASCII text, resulting in an array of chars instead of numbers. In the example script, this has been used directly, but if the values are to be used in another format, the read data must be converted.
Finally, the script will close the serial communication as not to hold up the device for other use.
Closing the serial communication.
The script itself will try to identify the connected Virtual Serial Port number using the VID and PID used in the MCC setup. If it throws an error, or the VID or PID is changed, the script has an optional argument -s
that can be used to input the number. This is exemplified below:
python usb_cdc_virtual_serial_port.py -s COM10
By following this example, the user will:
- Understand the basics of CDC communication on the AVR DU.
- Be able to create simple applications where CDC is the communication protocol between host and device.