📜 ⬆️ ⬇️

USB hardware module in ATXMega. HID Implementation Guide

The Atmel USB hardware module in eight-bit microcontrollers appeared a long time ago. But I did not find a clear guide “step by step” in Russian for the XMega family of controllers. Therefore, I share my experience. The experience is rather superficial, however, it allows developers who have no opportunity to delve into the subtleties of the USB stack, in a short time to ensure the interaction of the controller with the computer via the USB interface. There are videos on the Atmel channel on YouTube like this. However, many are more comfortable to read than watch a video - this post is for these people. Also, I will describe the implementation on the PC side.

IRON. I used the ATXMega256A3BU controller. This is the same ATXMega256A3, but with a hardware-implemented USB module. By the way, I thought they were pin-to-pin compatible, but this is not completely true, be careful! I connected the outputs of the D + and D- controller directly to the corresponding pins on the computer connector without any resistors. In my case, however, there was not a computer, but a USB hub chip, and then a computer, but I do not think that this significantly changes things.

SOFT MICROCONTROLLER. To create the backbone of the firmware, with the Atmel USB stack already implemented by programmers, we will use the ASF Wizard, which is built into the Atmel Studio 6 version. Day start, you must create a new project (File-> New Project). Next, in the window that opens, select the items shown in the picture.

image
')
After creating a new project, you need to run the ASF Wizard (menu ASF-> ASF Wizard). In the tab of the tabs, you need to find the USB Device (service), and click Add. After that, a USB Device (service) will appear in the Selected Modules tab, and a drop-down list next to it. In it, select hid_generic. Then click on the Summary button, and on this the creation of the project is completed. Now he is ready to fill it with meaning. In the main project file main.c we will see the following content:

#include <asf.h> int main (void) { board_init(); // Insert application code here, after the board has been initialized. } 

The board_init () function initializes the debug board, XMEGA-A3BU Xplained. Since I did not have this board, but my own, I threw out this function. Next we need a function to initialize USB. This is udc_start (). It is declared somewhere in the depths of asf.h, so we calmly write it down. It initializes USB according to the settings described in the conf_usb.h file. This file is located in the project folder. Here are the lines of this file that are particularly important for configuring USB HID:

 #define USB_DEVICE_VENDOR_ID 0x03EB #define USB_DEVICE_PRODUCT_ID 0x2013 #define USB_DEVICE_POWER 500 // Consumption on Vbus line (mA) #define USB_DEVICE_ATTR USB_CONFIG_ATTR_SELF_POWERED #define USB_DEVICE_MANUFACTURE_NAME "Company Name" #define USB_DEVICE_PRODUCT_NAME "Varior Lens" #define USB_DEVICE_SERIAL_NAME "00001" #define UDI_HID_GENERIC_REPORT_OUT(ptr) my_callback_generic_report_out(ptr) extern void my_callback_generic_report_out(uint8_t *report); #define UDI_HID_REPORT_IN_SIZE 64 #define UDI_HID_REPORT_OUT_SIZE 64 #define UDI_HID_REPORT_FEATURE_SIZE 4 


Define names speak for themselves. Information about what vendor id and product id in the network is enough. UDI_HID_REPORT_IN_SIZE and UDI_HID_REPORT_OUT_SIZE are the sizes of the input and output buffers, respectively. The my_callback_generic_report_out () function is called when the data packet is received from the computer. It can process the received data.

After USB is initialized, it can be used. The program code generally looks like this:

 #define F_CPU 32000000UL #include <asf.h> int8_t ui_hid_report [64]; uint8_t report [64]; void my_callback_generic_report_out(uint8_t *data){ for (uint8_t i = 0; i < 64 i++){ report [i] = data[i]; } //    report      } void main(){ irq_initialize_vectors(); cpu_irq_enable(); sysclk_init(); udc_start(); sysclk_enable_module(SYSCLK_PORT_C, SYSCLK_TC0); //    0 while(1){ //      ui_hid_report   udi_hid_generic_send_report_in(ui_hid_report); } } 


I will say a few words about the sysclk_enable_module line (SYSCLK_PORT_C, SYSCLK_TC0). The fact is that the sysclk_init () function by default turns off the clocking of most of the peripherals. I could not figure out what principle she does, but figured out how to turn the periphery back :) You can use sysclk_enable_module () and add what you need to include as arguments. You can understand what exactly to add if you use search in the whole project and specify sysclk_disable_module as a search parameter.

If you pour this code into the controller and connect it to the computer, then a HID-compatible device will appear in the device manager. And in devices and printers, a device with the name that was specified in the line #define USB_DEVICE_PRODUCT_NAME. In my case, it looks like this:



SOFT FOR COMPUTER.

All the same Atmel kindly provides us with examples of how to do it on the side of the company. They are made in Visual Studio, in which I am not strong, so I had to rewrite under C ++ Builder. On this occasion, colleagues said to me: "Get out." But the rich and happy. In general, I give an example on the builder.

The first step is to connect the library AtUsbHid.dll. It should be taken in the folder with the atmelovsky example and dropped into the folder of your project. To begin with, in the .h project file in the appropriate places we write the following lines:

 typedef ULONG HIDStatus; typedef HIDStatus WINAPI __import tcloseDevice(void); typedef HIDStatus WINAPI __import tfindHidDevice(const UINT VendorID, const UINT ProductID); typedef HIDStatus WINAPI __import twriteData(UCHAR* buf); protected: tcloseDevice *closeDevice; tfindHidDevice *findHidDevice; twriteData *writeData; 


Further in the body of the program, for example, when creating a form, you need to write the following.

 HINSTANCE AtUsbHidhandle; AtUsbHidhandle = LoadLibrary("AtUsbHid.dll"); if (AtUsbHidhandle == 0) ShowMessage("  AtUsbHid.dll"); else{ closeDevice = (tcloseDevice*)GetProcAddress(AtUsbHidhandle,"closeDevice"); findHidDevice = (tfindHidDevice*)GetProcAddress(AtUsbHidhandle,"findHidDevice"); writeData = (twriteData*)GetProcAddress(AtUsbHidhandle,"writeData"); } 


Now we have functions for working with HID devices. findHidDevice (VID, PID) searches the system for a device with the corresponding VID and PID. After that you can work with them. writeData () sends an array to the device. You can use all this for example:

 #define VID 0x03EB #define PID 0x2013 char a = 0; a = findHidDevice(VID, PID_1); if (a != 0){ Label1->Caption = ""; } UCHAR leds[64]; leds[0] = 255; leds[1] = 10; leds[2] = 20; leds[3] = 30; writeData(leds); closeDevice(); 


That's how I implemented the HID device on ATXMega. Of course, the article does not reveal the subtleties and nuances of USB settings. However, now, those who are just starting their acquaintance with this topic have instructions for action, and further, pick and understand your cards!

And of course at the end of the video is sure how it works for me. Video camera with adjustable zoom, focus and aperture.

Source: https://habr.com/ru/post/221839/


All Articles