Real simple AVR circuits with USB
The V-USB project is a really interesting project. It's goal is to provide free source code to implement USB 1.1 in a AVR processor, this makes it possible to build cheap devices that can connect to a PC. It's possible both to send commands from the PC and to recieve data from the cpu. On the homepage there are a list of projects build on this technology. The circuits used a really simple. Often the Atmega8 is used, it has several I/O-ports and a decent amount of memory. Other choices are the small ATTiny 8-pins like the ATTiny45. This series are cheap, but have a drawback in the limited number of I/O-pins. Two pins are used for power, one is the reset pin. Another two is used for the USB-connection, which leaves us with three I/O's for connecting other stuff. Enough for a RGB-led, but not more. Another drawback is in the develop process, as the USB D+ and D- in most cases are connected to PB0 and PB2, which is also MOSI and SCK. This makes it hard to use ISP-programming. The ATTiny25 are also limited in use due to it's small memory, the USB-code leaves a few hundred bytes for other code. The ATTiny2313 is also usable, more I/O but still limited memory. Example: http://www.delta7.de/projekte.php#usblcd A commonly used cpu is the ATMega8, here we have plenty of memory and many I/O's at a reasonable price. Read more at http://www.obdev.at/products/vusb Host software A little theory about the software used. USBRelay (Link) is used as an example. 1 - count.c. The number of arguments are checked. if (argc != 1) The USB device is initiated, if it fails an error is raised: if (usbrelay_init()!=0) { printf("%s\n", usbrelay_strerror()); If all ok: printf("%i\n", usbrelay_count()); uchar usbrelay_count() is found in the file lib/usbrelay.c. Here this code is run: usb_do(USB_ENDPOINT_IN, REQUEST_COUNT, 0, &result, 1); return result; usb_do is in this file too: static int usb_do(int direction, int request, char value, char *data, int len) Later in usb_do the following is run: i= usb_control_msg(usb_handle, USB_TYPE_VENDOR | USB_RECIP_DEVICE | direction, request, value, 0, data, len, USB_TIMEOUT); -usb_handle, // handle obtained with usb_open() -USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN From Libusb (/usr/include/usb.h): #define USB_TYPE_VENDOR (0x02 << 5) #define USB_RECIP_DEVICE 0x00 #define USB_ENDPOINT_IN 0x80 -request = REQUEST_COUNT // bRequest In usbrelay.h we find this line: #define REQUEST_COUNT 0 So in this case the request is GET_STATUS (0x00). -value // wValue. Depends on request type. -0 - wIndex -data - pointer to destination buffer -len - In USB-language called wLength, V-USB calls this numBytesRequested. USB_TIMEOUT - timeoutInMilliseconds. usbrelay.c: #define USB_TIMEOUT 1000
To get more practical. In the host software we use this function to request a value from the usb-device: static int usb_do(int direction, int request, char value, char *data, int len) { int i; while (len > 254) { usb_do(direction, request, value, data, 254); data+= 254; len-= 254; } i= usb_control_msg(usb_handle, USB_TYPE_VENDOR | USB_RECIP_DEVICE | direction, request, value, 0, data, len, USB_TIMEOUT); if (i < 0) { snprintf(str_error, sizeof(str_error), "usb error: %s", usb_strerror()); return i; } return 0; } The code to call the function looks like this: uchar result; usb_do(USB_ENDPOINT_IN, REQUEST_COUNT, 0, &result, 1); The variable result will hold the data from the device. '1' is the numBytesRequested, ie how many bytes we like to receive.
Device software From V-USB wiki: "When the host sends or receives a control message on endpoint 0 which is addressed to "vendor" or "class", the function usbFunctionSetup() is called in your code.". This is just what our host software will do. In the function we can use a switch-instruction to determine what to do: switch(rq->bRequest){ In this code we also find: #define REQUEST_DEVICE_COUNT 0 This is the same as REQUEST_COUNT in the host code. and can be any number. The USB Relay host code also has this: #define REQUEST_SET 1 and in device code we find: #define REQUEST_SET_RELAYS 1 The conclusion is that the device can run different code depending in the value of rq->bRequest: case REQUEST_DEVICE_COUNT: ... case REQUEST_SET_RELAYS: ... Reference: http://vusb.wikidot.com/host-software, http://www.beyondlogic.org/usbnutshell/, http://dormouse.org.uk/sw/cyberphone.php