UART was a popular serial interface in the past times. Still, a lot of embedded system devices uses UART for serial communication. However nowadays, the personal computers do not have RS-232 ports but have only the USB ports for serial communication. In this project, an UART to USB converter is designed to enable connecting embedded devices having UART interface to the personal computers. The project device works like a virtual serial device. That means that the data packets from the host computer are received according to the USB protocol and data packets from the connecting embedded device are received according to UART protocol but the project device will change the protocol in-between while the PC will be acknowledged that it is connected to a USB peripheral and the connecting embedded device will be acknowledged that it is connected to a computer having UART interface. The 8-bit USB AVR – Atmega 32u4 is used as the controller chip in the project. The project uses AVR based Lightweight USB Framework (LUFA) as the firmware which will be modified to perform the protocol conversion.
The LUFA’s communication device class (CDC) is modified to program the project. By using the LUFA firmware, the device driver code to implement USB protocol and the UART protocol will not needed to be written explicitly. By only using an API provided in the open source framework, the conversion between the protocols will be done.
Fig. 1: Prototype of Arduino Based USB to UART and UART to USB Converter
The device does to need any human inputs. The USB data is received by the project device from the USB port of the Arduino Pro Micro. For UART, Tx and Rx pins of the Arduino Pro Micro are connected with the UART interface of the connecting embedded device.
This project is based on Arduino Pro Micro which has the USB AVR – Atmega 32u4 as the sitting MCU. In order to understand this project, one must have basic knowledge of the AVR microcontrollers and the embedded C programming for AVRs. WinAVR Studio is used to write, edit and compile the project code, so closely following the project shall require familiarizing with the above stated IDE as well. Though LUFA framework takes care of implementing the USB protocol as well as UART protocol and has APIs to abstract the lower level codes, understanding USB protocol is recommended to understand how actually the project is working. In fact, if anyone has already worked on some other microcontroller, it will not be much pain to understand and follow the project. The project is based on using APIs of the LUFA framework and modifying the demo files that comes with the framework itself.
Fig. 2: Image showing characters sent by Arduino to PC via Serial Device
1. Arduino Pro Micro
2. Connecting wires
3. Micro USB cable
SOFTWARE TOOLS REQUIRED
1. WinAVR Studio
2. AVR Dude
Fig. 3: Block Diagram of Arduino based USB to UART and UART to USB Converter
The project is built on Arduino Pro Micro in which Atmega 32u4 works as the controller chip. The USB to UART and UART to USB protocol conversion is carried out on the Arduino board itself. The Arduino board has in-built USB port to connect with the personal computer and has Tx and Rx pins for serial communication on UART. So only the Arduino board is needed and connecting wires for connecting with embedded device having UART interface and USB cable for connecting with the PC are required. The Program code for the project is burnt to the Arduino Pro Micro using AVR Dude. Once the firmware is loaded to the Arduino board, it can be used for UART to USB and USB to UART conversion.
HOW THE PROJECT WORKS
In this project both USB and UART protocol are used and an API of virtual serial device from the LUFA framework is employed to implement the project. The device is configured to communication device class (CDC). For USB to USART and USART to USB conversion, the device is configured to Abstract Control Model Subclass.
The USB communications device class (CDC) is a composite USB device class, and the class may include more than one interface. The CDC is used primarily for modems, but also for ISDN, fax machines, and telephony applications for performing regular voice calls. The Abstract Control Model subclass of CDC bridges the gap between legacy modem devices and USB devices, enabling the use of application programs designed for older modems.
Fig. 4: Image of Arduino Based USB to UART and UART to USB Converter
The project is USB CDC class device. In the LUFA framework CDC class related modules are in the LUFA-Source-Folder /LUFA/Drivers/USB/Class/Device folder. Other device class related module are also in the same folder. The LUFA framework has demo projects for different USB device classes in the LUFA-Source-FolderDemosDeviceClassDriver folder. For implementing the project, demo project for virtual serial device provided in the LUFA framework will be modified and complied. The demo project for virtual serial device is in the LUFA-Source-FolderDemosDeviceClassDriverVirtualSerial folder. The folder contains VirtualSerial.c file which will be modified to implement the project.
How VirtualSerial.c identifies device a CDC USB Device
The VirtualSerial.c uses VirtualSerial_CDC_Interface interface in CDC_Device_USBTask () function which is being imported from the CDCDeviceClass.c (from LUFA-Source-Folder LUFADriversUSBClassDevice) to configure the device as USB CDC device. The interface abstracts the low-level descriptor codes and identifies the device as CDC device through an InterfaceNumber variable.
USB CDC Specific Descriptors
Like any HID device configure and exchange data with the host by sending descriptors in response to requests from the host device, the USB CDC devices also connect with a host via request-descriptor mechanism. At application layer descriptors are structured in the form of reports. Every report descriptor has a report structure. A report descriptor contains the information needed by host to determine the data format and how the data should be processed by the host. Therefore, a report descriptor basically structure the data that needs to be exchanged with the host according to the USB protocol.
When an USB CDC device is connected to the host computer, the host sends request for configuration in the form of control transfer. This is common for all USB peripherals or devices. Any CDC device for configuring with a host has to respond with Class Request, Class Notification and Endpoint Configuration. These information are passed through the Usage report to the host as the Usage Report informs the Host about the features or functionality of the USB device.
The usage and data report associated with CDC USB devices are defined in the CDCClassCommon.h file in the LUFA framework. The file is located in the LUFA-Source-Folder/LUFA/Drivers/USB/Class/Common folder. The CDC class allows an USB device to connect with various other interfaces and protocols like for the ISDN, fax, Ethernet, telephone etc. In the usage report, a CDC device has to acknowledge its class, subclass and protocol values.
In CDCClassCommon.h, the subclass protocols of the CDC class are mentioned through an enum CDC_Descriptor_ClassSubclassProtocol_t in the following manner.
Fig. 5: Screenshot of CDC_Descriptor_ClassSubclassProtocol_t Descriptor
The device designed in this project uses Abstract Control Model (ACM) protocol. By LUFA, any CDC class device can respond to following control requests.
1. Send Encapsulated Command
2. Get Encapsulated Response
3. Set Line Encoding
4. Get Line Encoding
5. Set Control Line State
6. Send Break
These codes for these requests are mentioned in the LUFA in the following manner.
Fig. 6: Screenshot of Codes for requests of Abstract Control Model (ACM) protocol
Of these, the ACM subclass device responds to only three control requests.
Fig. 7: Table listing control requests of ACM Subclass Device
The descriptor in response to Set Line Coding request has the following field values.
Fig. 8: Table listing fields of descriptor in response to Set Line Coding request
The descriptor in response to Get Line Coding request has the following field values.
Fig. 9: Table listing fields of descriptor in response to Get Line Coding request
The descriptor in response to Set Control Line State request has the following field values.
Fig. 10: Table listing fields of descriptor in response to Set Control Line State request
For ACM Subclass CDC devices, the line coding structure is defined in the following manner.
Fig. 11: Table listing line coding structure of ACM Subclass CDC devices
The Set Line Encoding request allows the host to specify typical asynchronous line-character formatting properties while get Line Encoding request allows the host to find out the currently configured line coding. The ACM line encoding format mentioned above is received or sent to the host from the device in the data packet of the descriptors responding to Set_Line_Coding and Get_Line_Coding requests respectively.
For line coding scheme, in LUFA, the CDC_LineEncodingFormats_t enum defined in CDCClassCommon.h has the character format values defined in the following manner.
Fig. 12:Screenshot of CDC_LineEncodingFormats_t enum defined in CDCClassCommon.h
In CDCCLassCommon.h only, the CDC_LineEncodingParity_t enum has the values for parity type defined in the following manner.
Fig. 13: Screenshot of values for parity type defined in CDC_LineEncodingParity_t enum in CDCClassCommon.h
The control signal bitmap which is sent on Set Control Line State request has the following format in its descriptor.
Fig. 14: Table listing control signal bitmap sent on Set Control Line State request
These requests are made by the host when the device acknowledge itself to be a CDC class device. After configuring as ACM subclass, the device has to respond to a class notification to the host to describe the type of interface. For ACM subclass, following notification is received from the host.
Fig. 15: Table listing notification received from the host for ACM Subclass
Again device responds with a descriptor having the following Field Values.
Fig. 16: Table listing descriptor responded by the USB device
The UART bitmap sent in the descriptor responding to the Serial_State notification has the following format.
Fig. 17: Table listing Serial_State notification of UART bitmap sent in the descriptor
In CDCCLassCommon.h, the descriptor sent by the device to configure device as CDC subclass device in the form of a data report is defined in the following manner.
Fig. 18: Screenshot of data report in CDCCLassCommon.h
The descriptors specific to a subclass have the following data report definition.
Fig. 19: Screenshot of data report definitions
The data reports for configuring to ACM subclass has been defined in the following manner in CDCClassCommon.h.
Fig. 20: Screenshot of data reports for configuring to ACM subclass in CDCClassCommon.h
The descriptors specific to ACM subclass have the following data report definition in the CDCClassCommon.h.
Fig. 21: Screenshot of descriptors specific to ACM subclass in CDCClassCommon.h
How a CDC Class device is enumerated can be understood from the following endpoint configuration table.
Fig. 22: Endpoint Configuration Table for CDC Class device
Therefore, when the device is connected to the computer, first through control transfer at endpoint zero, host makes standard request and class requests to which the device responds with descriptors mentioned above. Then through an interrupt transfer at endpoint 0, the device sends another descriptor to the host and notifies it for serial interface and communication. The descriptor for state notification has also been already described above. After the state notification, the device and host get configured to carry out bulk transfers for data transmission between them.
The data reports that are sent to the host in bulk transfers for data transmission between the host and device have definition according to the following structure defined in CDCClassCommon.h.
Fig. 23: Screenshot of Data Reports in CDCClassCommon.h
From Where VirtualSerial.C gets the USAGE and Data Report Descriptors
In the LUFA framework’s demo project for Virtual Serial, VirtualSerial.c file imports VirtualSerial.h where the descriptors.h is imported. The descriptor.h has the structures defining CDC class related descriptors which have been explained above. The VirtualSerial.c imports VirtualSerial.h which imports usb.h. USB.h imports CDCCLass.h. In CDCClass.h is imported CDCClassDevice.h. The CDCClassDevice.h imports CDCClassCommon.h where the CDC device specific descriptor fields have been defined.
HOW THE DEVICE WORKS
The device needs to be connected between the PC and the embedded system having UART interface. The Arduino board itself is the complete project device. In the project code additional library for UART is imported and the main() function of the VirtualSerial.c is modified to work the device like a protocol changer. Check out the program code to see the modifications implemented for building the project.
For building the project download the LUFA framework from the github.com. The demo project provided with the LUFA framework is modified to make the device. In the extracted LUFA zip file, open Demos/Device/ClassDriver/VirtualSerial folder. The folder has the following files and folders.
Fig. 24: Screenshot of LUFA Library Folder on Windows
Of these, VirtualSerial.h, VirtualSerial.c and Makefile needs to be modified for the project. The modified files (provided at the bottom of the article in zip format) can also be downloaded from the engineersgarage and replaced with the original files. Either open the files in WinAVR Studio or Notepad++ and modify original files or replace files with the already modified one. The modified or replaced VirtualSerial.c needs to be compiled from within the LUFA’s Source folder to get the object code.
The VirtualSerial.h library file is imported in the VirtualSerial.c file and includes a set of additional libraries and defines the constants and functions for the joystick device. These include the additional libraries for the joystick, button and LEDs which should be commented out as the project is not using these features. So open VirtualSerial.h and make the following changes – :
• Comment the #include library statements for Joystick.h, LEDS.h, and (We are commenting these libraries as we are not using any joystick, buttons board and LED board)
• Comment the #define statements for LEDMASK_USB_NOTREADY, LEDMASK_USB_ENUMERATING, LEDMASK_USB_READY, LEDMASK_USB_ERROR
• Delete the function declaration for CheckJoystickMovement Save the file with changes
Modifying VirtualSerial.C file
Again in the VirtualSerial.c, the code sections for Joystick, button board and LEDs need to be commented out. So open VirtualSerial.c and make the following changes – :
• In the main loop, comment the LEDs_SetAllLEDs()
• In SetupHardware() function, comment the Joystick_Init(), LEDs_Init()
• In EVENT_USB_Device_Connect() function, comment the LEDs_SetAllLEDs()
• In EVENT_USB_Device_Disconnect() function, comment LEDs_SetAllLEDs()
• In EVENT_USB_Device_ConfigurationChanged() function, comment the LEDs_SetAllLEDs()
• Also delete the CheckJoystickMovement function completely
In VirtualSerial.c the main() function executes the functioning of the protocol convertor device. First uart.h has to be included in the VirtualSerial.c So add the following statements in the beginning of file – :
The following functions defined in the uart.h will be used in the program code.
Fig. 25: Table listing functions defined in uart.h
In the main() function, a variable OUT_Data to hold data sent by the host needs to be defined and a character buffer buff to hold data from UART has to be defined. The array representing character buffer has to set its last element as NULL character and UART has to be initialized using uart_init() function. A file variable has to be defined to contain data received from the USB port. This has to be used as parameter in CDC_Device_CreateStream() function. The CDC_Device_CreateStream() function is defined in the CDCClassDevice.c file where other CDC Class Device related functions are also defined. The CDCClassDevice.c is located in the LUFA-Source-FolderLUFAUSBClassDevice folder. An infinite for loop is called in which data from USB port is assigned to OUT_Data variable using getc() function and is sent Tx pin of UART using uart_char() function. If any data from embedded device through UART is available, it is read through uart_read() function and is assigned to the buff. The data in buff is taken into ReportString pointer and sent to the computer using fputs() function. So replace the original body of the main function from the following code.