Code and Life

Programming, electronics and other cool tech stuff

Supported by

Supported by Picotech

AVR ATtiny USB Tutorial Part 4

All right. Now that we got the basic USB code working in part 3, it’s time to wrap things up in this tutorial series. This fourth section will explain how to send data from your device to PC and also the other way around. I may later do a fifth part on how to make a USB HID device like a keyboard or mouse, so if you haven’t already, I’d recommend subscribing to the RSS feed to get updates.

Sending data from device to PC

If you look carefully at our command-line client code, you probably noticed that the control messages sent to toggle the led are of type USB_ENDPOINT_IN and we have a 256-byte buffer in place to receive any data the device sends. So far we have not received any data and the return value stored in nBytes has been zero. Let’s change that.

If you read through the documentation in usbdrv/usbdrv.h, more specifically the comments for usbFunctionSetup() we used to toggle our LED on device side, you can see that there are two ways to return data from usbFunctionSetup():

  1. Set the global pointer usbMsgPtr to a (static RAM) memory block and return the length of data from the function
  2. Define usbFunctionRead() function to do it yourself

We will be using the first method. First we define an additional message USB_DATA_OUT and a static buffer to store the data we want to send from device to PC:


#define USB_DATA_OUT 2

static uchar replyBuf[16] = "Hello, USB!";

Then we add a new case to usbFunctionSetup() to return the contents of that buffer:


    case USB_DATA_OUT: // send data to PC
        usbMsgPtr = replyBuf;
        return sizeof(replyBuf);

Whoa, that was easy! V-USB does all the rest for us.

Now the only thing needed to do is to update our command-line client to include our new “out” command. Copy the #define from above to the beginning of usbtest.c (right after the existing two #defines is a good place) and add a third if statement to the main method:


    } else if(strcmp(argv[1], "out") == 0) {
        nBytes = usb_control_msg(handle, 
            USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN, 
            USB_DATA_OUT, 0, 0, (char *)buffer, sizeof(buffer), 5000);
        printf("Got %d bytes: %s\n", nBytes, buffer);
    }

Just run “make” and “make flash” to compile and update the firmware. Now try “usbtest out” – how easy was that? With 128 bytes of RAM on ATtiny and V-USB using a lot of that, you will not be able to transmit the maximum of 254 bytes this method offers (implement usbFunctionRead() to transfer longer buffers piece by piece), but even 16 characters is quite a lot! And of course you can chain multiple control requests if you want to receive more data.

Sending data from PC to device

If you only need to send a few bytes of additional data, you can use the wValue and wIndex parameters for that. Let’s make a new USB_DATA_WRITE that changes the “USB!” part of our return message to any four characters. First a new #define (add to both main.c and usbtest.c):


#define USB_DATA_WRITE 3

Then a new case to firmware side:


    case USB_DATA_WRITE: // modify reply buffer
        replyBuf[7] = rq->wValue.bytes[0];
        replyBuf[8] = rq->wValue.bytes[1];
        replyBuf[9] = rq->wIndex.bytes[0];
        replyBuf[10] = rq->wIndex.bytes[1];
        return 0;

Note that the wValue and wIndex are actually unions that allow you to either access the whole 16-bit word value with wValue.word or alternatively directly access the lower and upper bytes with wValue.bytes[0] and wValue.bytes[1], respectively (I’m not sure if the order of upper and lower bytes in the word depends on endiandness on PC side, but that’s how it works for me).

On command-line side, we add another “else if” that sends fixed letters for simplicity:


    } else if(strcmp(argv[1], "write") == 0) {
        nBytes = usb_control_msg(handle, 
            USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN, 
            USB_DATA_WRITE, 'T' + ('E' << 8), 'S' + ('T' << 8), 
            (char *)buffer, sizeof(buffer), 5000);
    }

Just compile with "make", update firmware with "make flash" and try out the new "usbtest write" command. Note that the command itself does not print anything, you need to run "usbtest out" before and after to see how the buffer is changed. Also note that until you reset or unplug the device, the new message "Hello, TEST" will stay in the device.

Sending more data to the device

Using wValue and wIndex is fine for many applications, but if we'd like to update the whole 16-byte buffer, we'd need at least four control messages. Let's now create our first USB_ENDPOINT_OUT message. On PC side the code is pretty simple:


#define USB_DATA_IN 4

...

    } else if(strcmp(argv[1], "in") == 0 && argc > 2) {
        nBytes = usb_control_msg(handle, 
            USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_OUT, 
            USB_DATA_IN, 0, 0, argv[2], strlen(argv[2])+1, 5000);
    }

Note that the buffer size is one more than just the argument 2 length to accommodate the string-terminating NULL character. On device side we add a new variable to keep track how many bytes we are to read, and use a special return value from usbFunctionSetup() (this is all well documented in usbdrv.h):


#define USB_DATA_IN 4

static uchar dataReceived = 0, dataLength = 0; // for USB_DATA_IN

...

    case USB_DATA_IN: // receive data from PC
        dataLength = (uchar)rq->wLength.word;
        dataReceived = 0;
		
        if(dataLength > sizeof(replyBuf)) // limit to buffer size
            dataLength = sizeof(replyBuf);
			
        return USB_NO_MSG; // usbFunctionWrite will be called now

Now that the request is of type control-out (USB_ENDPOINT_OUT on PC side code) and we have returned USB_NO_MSG (with byte-size return value it's actually 255, also the reason why data from device can be only 254 bytes tops), V-USB will call a function named usbFunctionWrite() to receive the data sent:


USB_PUBLIC uchar usbFunctionWrite(uchar *data, uchar len) {
    uchar i;
			
    for(i = 0; dataReceived < dataLength && i < len; i++, dataReceived++)
        replyBuf[dataReceived] = data[i];
		
    return (dataReceived == dataLength); // 1 if we received it all, 0 if not
}

Last thing to do is to modify usbconfig.h to tell V-USB we have provided such a function:


#define USB_CFG_IMPLEMENT_FN_WRITE      1

Now you should be able to remake and flash the project and use the new "usbtest in abcdefgh" command to replace the values in device's 16 byte buffer. Note that if you supply a string longer than 15 characters, the terminating NULL character will not fit into buffer and "usbtest out" may print out garbage after the 16 characters. This is just a demo application so we ignore that for now. :)

Final remarks

Congratulations! You have successfully built and coded a USB device that is able to receive commands and send/receive arbitary data. Once you have understood how V-USB calls usbFunctionWrite(), it should also be pretty straightforward to make usbFunctionRead() in similar manner to send longer data to PC in multiple parts.

I have compiled the Makefile and source code files as well as relevant portions of V-USB and libusb-win32 for compiling the project, as well as the final schematic into one .zip file:

usb_tutorial_20120204.zip

Update: If you don't for some reason like the command-line usbtest.exe, or would like to develop a graphical client, Günter Meinel has created an excellent GUI version of the test program using Borland C++ Builder 3.0. You can get it with source code from here:

http://home.arcor.de/guentermeinel/download.html

I hope you have enjoyed the tutorial, and hope to see you again on this site, I'm planning to write at least a bit about 7 segment LED multiplexing, driving LCDs directly with AVR, and PicoScope USB oscilloscope in the future, and may add new subjects as I get further myself.

This is the end of "the main arc" of my V-USB tutorial, but I recommend you to read my later posts in the V-USB tutorial series, including:

86 comments

Marek:

Hello,
I am sorry, but I cannot figure out how to use usbFunctionRead() along with the application in my PC… could you post here some really simple example how to send, let’s say like 1024bytes from the device to PC ? I am not getting how does the data i send appear in the buffer, or more generally, where it appears :D, I am sorry…
Thank you very much…
P.S.: I am not sure whether I understood well how to use usbFunctionRead() in the device or not…..

jokkebk:

@Marek
Hi,

usbFunctionSetup is capable of returning 254 bytes of data at most, so one possibility would be to return 128 bytes at a time over 8 calls (you could use wIndex to request a specific portion or just have an incrementing counter which part to send next). This of course requires a device with at least 256 bytes of memory, and you need to have 8 consecutive calls in PC side code, too.

For usbFunctionRead you first need to enable it in usbconfig.h and then define it in your main.c. Then you return USB_NO_MSG from usbFunctionSetup to indicate usbFunctionRead should handle sending the data. The read function is well documented in V-USB’s usbdrv.h – basically V-USB calls your function with a 8-byte buffer and length argument telling how many bytes it wants and you fill the buffer and return the amount of bytes stored in there until you run out of data, in which case you return 0 (or something less than 8 if you had some odd bytes left).

I’ll try it out when I have my breadboard free again and add a short new tutorial on this.

dani:

I has try to build this several time without luck. I has built it with ‘make main.hex’ and do ‘make flash’, but when I try to connect to the usb port computer said ‘usb not recognized’ and detected as ‘unknown device’ with both vendor and product id 0x00. I didn’t use regulator to droping usb voltage, but I use zener diode connected to d- and d+ pin (as shown at vusb example schematic), anyone can help?

jokkebk:

@dani
I had the same issues when my port pins were incorrect in usbconfig.h – or actually they were correct, but usbdrv.o and usbdrvasm.o did not recompile automatically because “make” didn’t understand they depended on usbconfig.h… So first thing I’d do would be to double-check that D+ and D- are corrected to right pins, remove the .o files, recompile and see if it helps.

I assume you have the 2k2 pullup in D+ also with zener setup? I just tried the zener diode setup yesterday myself and it seemed to work nicely. Only other thing I could guess would be that crystal is not exactly 12 MHz which could cause the V-USB to fail…

Marek:

@jokkebk
Hello,
Thank you very much! I will help me a lot.

Marek

Gunner:

Thankyou very much..

Damian:

Hi, i have problem. I bulid powerswitch but it does not work. Windows not recognize the device (unicown device code 22). I do everything as in this guide. Processor it’s AtMega8A-PU

changes in the usbconfig.h

#define USB_CFG_IOPORTNAME D
#define USB_CFG_DMINUS_BIT 6
#define USB_CFG_DPLUS_BIT 7
#define USB_CFG_CLOCK_KHZ 16000
#define USB_CFG_IS_SELF_POWERED 0
#define USB_CFG_MAX_BUS_POWER 50

fuse bits set as:

# ATMega8 FUSE_L (Fuse low byte):
# 0x9f = 1 0 0 1 1 1 1 1
# ^ ^ \ / \--+--/
# | | | +------- CKSEL 3..0 (external >8M crystal)
# | | +--------------- SUT 1..0 (crystal osc, BOD enabled)
# | +------------------ BODEN (BrownOut Detector enabled)
# +-------------------- BODLEVEL (2.7V)
# ATMega8 FUSE_H (Fuse high byte):
# 0xc9 = 1 1 0 0 1 0 0 1 <-- BOOTRST (boot reset vector at 0x0000)
# ^ ^ ^ ^ ^ ^ ^------ BOOTSZ0
# | | | | | +-------- BOOTSZ1
# | | | | + --------- EESAVE (don't preserve EEPROM over chip erase)
# | | | +-------------- CKOPT (full output swing)
# | | +---------------- SPIEN (allow serial programming)
# | +------------------ WDTON (WDT not always on)
# +-------------------- RSTDISBL (reset pin is enabled)

jokkebk:

Sorry, I cannot help you much. Only thing I noticed that you have quite quick delay in your fuse settings (SUT=01 resulting in 16k clock cycles + 0 ms) – you might want to try the ones like +4ms and +64ms (SUT=10 and SUT=11) and see if that helps.

And of course, if you’ve customized anything from my example to suit the PowerSwitch project, double-check that the D+ and D- settings are OK, etc. You might also want to try a simple program that just blinks a LED every 10 seconds to see that the crystal and fuse are working together correctly.

Also note, that D+ should be also connected to INT0 pin of the ATmega (see PowerSwitch schematic for an example of this, I recall they wired it to both that pin and another pin), in your case it seems to be PD2 – if that’s not the case, it will not work!

Damian:

I wrote on this page that have changed and how I made PCB board. (My nick is myndoza, no registration neded).

http://www.elektroda.pl/rtvforum/viewtopic.php?p=10730110#10730110

Odłaczyłem zenerki – nic ->zener diode disconect – no change
Odłaczyłem rezystorek R12 (1M) – nic ->1M resistor disconect – no change
Podłączyłem rezystorek R12 bez zenerek – nic ->1N connected, zener disconect – no chgange
1M resictor conected to GND, zeners disconect – no change
1M resictor conected to GND, zeners conect – no change
Change power supply of 5V to 3,5V with two rectifier diodes (5V->diode->diode->3,5V)- no change
I add capilator(4,7uF/50V electrolytic & 100nF – ceramic) between 5+V & GND – no change

I used the program, the change of status LEDs. She blink a frequency of 1 Hz

PS I changed FB (at SUT 10 or 11)- no change

jokkebk:

Sorry, seems like everything _should_ be OK. You probably made sure the files in usbdrv have been recompiled since changing usbconfig, so the only remaining idea would be that maybe it’s just the PowerSwitch driver that doesn’t work with 64 bit Win7?

Instead of the PowerSwitch firmware, you could try either the ones I have in USB tutorial or HID mouse tutorial, they have 64 bit drivers in the zip file.

Damian:

Ok I’m running example hid mouse jupi. Propably i was soldering zener’s in wrong way. Now i have problem in PowerSwitch. He dosen’t work anyway. I use the same makefile and usbconfig as HID-mouse :(. I don’t have a idea why this dosen’t work.

jokkebk:

Nice to hear that you got the device to work in some configuration already! No idea either why the PowerSwitch doesn’t work, are you sure it’s not a driver issue? You could take a look at my USB tutorial part 3 where I build custom drivers for my device, you could probably do that for PowerSwitch to get 64-bit drivers for that.

Also, note that the HID mouse usbconfig says it’s a HID device and it also probably has a completely different vendor and product IDs – so only copy the beginning of HID example usbconfig to your PowerSwitch usbconfig. :)

Joseph:

Sir please provide the host side software code for Visual Studio C++ with a form. Please I beg your kind honor.

Thanking You.
Regards.

jokkebk:

You had accidentally double-posted, I removed the first comment.

I unfortunately do not have Visual C++ at hand, but I assume linking libusb-win32 and getting my example code to compile should be fairly straightforward.

A graphical user interface in Windows using C++ is unfortunately something I haven’t done, and I don’t have the 3-5 hours to devote to it currently. I might do that in some point in the future, but no guarantees at this point.

Joseph:

Thank you sir for your reply. Your tutorials are fantastic, but unfortunately I am facing problem in using MiniGW and so I have to use Visual Studio with C++. But I hope I can use your code in VC++ after using other message dialog in place of fprintf. Do I need to implement any other modification.. I will place your code in a new form application that I will make.

Sorry for the double post, it happened accidentally.

Thank You Sir.
Regards

jokkebk:

I see. I think VC++ should work fine after replacing printf. I think you could even make it a console application if you wanted, I recall Visual Studio had that as one option.

I don’t see any other changes, although you need to find out how to add libusb-win32 to your project, otherwise the compiler will complain about not finding the relevant functions. But that is just usual stuff and nothing specific to my tutorial. :)

Good luck in your conversion!

Joseph:

Sir, thankyou.

I would try to use VC++ and if I am successful then I would inform you what I have done so that you can forward it to those who are in need like me, right now.

Thank you..
Regards

Kyriako:

Hello Joonas,
well done!
This is a great HOW-TO for creating projects.
As I’m not a big fan of commandline programs, so I have programmed a GUI version of usbtest.exe.
Download:http://home.arcor.de/guentermeinel/experimental.html

I have already been working with a libUSB device: the “usbprog v.3.0”.
See http://shop.embedded-projects.net/ ->Open Source Projects->USBprog (in German)
I use this device as “AVR-ISP mkII clone” adapter for programming AVRs.
As programming software I use the avrdude.
Unfortunately, this software does not program AT90S1200 processors correctly. It even destroys the signature.
This will probably be fixed with the next version(presently, I have v.5.11).
Therefore, I adapted my old homebrew-programmer to work with the AVR-ISP mkII adapter.
If anyone is interested on how to do this, a simple test-implementation is available on my above mentioned experimental page.
It should also work with the original AVR-ISP mkII adapter. However, I can not verify that.

Regards
Kyriako.

Mia:

I am planning to do a project on USB based Datalogger and it will probably have 5( max) sensor inputs. The in-system self programmable flash memory of ATtiny2313 is just 2Kb which seems insufficient for my project.Can I replace ATtiny2313 with Atmega32?Will your tutorial work in that case too?I have never tried a project based on USB or AVR but after going through your tutorial, I believe my first attempt would be a lot simplified with the help of this tutorial. Thank you for posting this enlightening tutorial.

jokkebk:

Yes the V-USB should work nicely with an ATmega, too. I’ve used ATmega88 myself a lot, it’s cheap and has 28 pins which means plenty of inputs. No experience on ATmega32 but probably works just as well.

saurabh:

Hi sir,
Your tutorials are simply awsome!!!
You really did a commendable job.. Along with the informative techy part, You explained it all so well, i mean the writing part!!!
For a noob like me :(, it is sort of an awsome step by step guide..

Regards

erko:

(Thanks to http://www.sajidmc.net/2010/08/compiling-v-usb-avr-usb-example-program.html)
Copy \libusb-win32-bin-1.2.4.0\lib\MSVC\libusb.lib
to C:\Program Files\Microsoft Visual Studio 10.0\VC\lib\libusb.lib
Copy \libusb-win32-bin-1.2.4.0\include\usb.h
to C:\Program Files\Microsoft Visual Studio 10.0\VC\include\usb.h
Select New -> Project -> Win32 Console Application
Name: set-led
Location: \My Documents\Visual Studio 20xx\Projects\vusb-20100715\examples\custom-class\commandline
Solution name: set-led
Next>
Console application, NO precompiled header, Finish
Select View -> solution explorer
Right click Header Files -> Add -> Existing Item -> opendevice.h
Right click Source Files -> Add -> Existing Item -> opendevice.c & set-led.c
Right click Source Files -> Add -> Existing Item -> set-led.c
Double click set-led.c
Find & Replace (Ctrl H) strcasecmp -> strcmp (4 times)
Select set-led Properties (Alt+F7):
Configuration: Active(Debug)
Platform: Active(Win32)
Configuration Properties -> Linker -> Input ->
-> Additional Dependencies, click …, add: libusb.lib -> ok -> ok
Select Build Solution (F7)

Rokta:

Hi, I downloaded you project but when I tried to make it I got this error:

> “make.exe” all
gcc -I ./libusb/include -L ./libusb/lib/gcc -O -Wall usbtest.c -o usbtest.exe -lusb
process_begin: CreateProcess(NULL, gcc -I ./libusb/include -L ./libusb/lib/gcc -O -Wall usbtest.c -o usbtest.exe -lusb, …) failed.
make (e=2): The system cannot find the file specified.

make.exe: *** [usbtest.exe] Error 2

I didnt change any files or move them. Can you tell me what I did wrong?

jokkebk:

Hmm, weird. There are three things from the top of my mind that could be wrong:

1. You’re running the command in wrong directory
2. “make” is installed improperly
3. “gcc” (MinGW version for PC) is not installed

You should be in the project’s directory, and “make.exe”, “gcc.exe” etc. should be somewhere else, where the MinGW installer program has put them. Try running just “make” (without the quotes) and “gcc” to check that they don’t give any “not found” messages.

Rokta:

Thank for reply. It was problem with minGW. More precise I didn’t add minGW directory to PATH variable.

starkwood:

Hi, I see u ve done a great job here but I use pics a lot than avrs so I believe I could port ur apps to pics but the most important thing I want to achieve with dis is a programmer.I want a vusb pic programmer dats hid compliant.My major challenges are data transfers to n from host to d device n most importantly how to do io on the pins.Tnx

jokkebk:

Data transfer from host to device in a HID-compliant device is indeed slightly trickier subject. I think there are some other HID devices than mouses and keyboards, which can be “abused” to transfer more data than just “caps lock presses”. I’d look around V-USB pages and possibly ask in their forums about that.

Ricky:

Thanks for this tutorial. I want to make USB to Serial converter using Attiny2313 and VUSB. Could you give me tutorial or example? Or please give me links. I read about AVR-CDC, but i think it’s low speed.

jokkebk:

Unfortunately that is quite a complex topic: You’d first need to implement reading and writing to device and then have some buffers for incoming and outcoming data – those techniques have mostly been covered in the tutorial though. But you would also need to make custom drivers for your device, and I have no knowledge on how to implement for example a Windows virtual COM port. Good luck in your project, however!

studyembedded:

This is one of the best tutorial i have seen in these days…keep it up!

SAYED:

Hi,
It is very nice tutorial which it make the things easier to understaing by going step by step.really I learend so many things….Thank you for your help and I hope to you go up and up.

I have small quastion about usbconfig.h,

If I want to make mouse and keyboard both at a same time,What should I change and how about the IDs?

jokkebk:

That’s harder to do. It’s possible to make a USB compound device that has two descriptors, one for mouse and other for keyboard I think, and I’ve also understood that you can make a device that can send both key and mouse data in one report. However, I don’t have the knowledge how to do that – you’ll need to google around and maybe study the USB specification in much more detail than I have.

SAYED:

Finally ,I did it well and now its work as both

I go over your tutorial step by step and also I take your advising for searching in google ..

Thaks a lot

jokkebk:

You’re welcome; glad to hear that you got it working! If you have some good sources for the keyboard+mouse combo, feel free to post a link here also, might be useful for others, too. :)

Metin:

This tutorial helped me a lot! I did the whole thing without problems. Thanks!

Mia:

Hi,
Could you please clear out my confusion?What is the maximum packet size of the device?Is it 8 bytes or 16 bytes? is the data saved in replyBuf in device sent at once or in packets?

Hung:

Hello there,
When can we expect Part 5, making it a HID. Those driver issues are a pain and make it difficult to deploy on Mac, Win, and Linux.

Hung:

Additional comment re: making it a HID. Specifically I would be interested in seeing the code changes needed for either the mouse or the keyboard, to make it a RAW_HID device.

jokkebk:

There are already posts on making a USB HID mouse and keyboard. Did you have something else in mind?

Sending data using pseudo-HID devices has been documented elsewhere, I thought that once one gets the basics with this tutorial, that shouldn’t be too hard issue to tackle anymore. :)

jokkebk:

As the return value for replyBuf size is a unsigned char and 255 is reserved for special use, 254 bytes is the maximum with V-USB, I think. However, replyBuf has been defined in my code to be 16 bytes, so unless you change the definition, it’s exactly that size.

I don’t know how V-USB sends the USB data – I would assume it’ll send all 1-254 bytes of replyBuf in one go, but it could divide that up somehow – you’d need to study the USB specification in detail and understand that (I haven’t done that and thus do not know :).

Note that replyBuf size is in no way related to size of packets sent TO the device – the normal control message has room for 8 bytes of parameters that can be sent TO the device – and you can receive more (as well as send more) using the usbFunctionRead() and usbFunctionWrite() mechanisms (those are called multiple times, so at least in a way longer data streams are sent in “packets” with V-USB, although I’m not sure if the PC sees the data as just one long transmission).

Hope this clears it up at least a little. The USB protocol is quite a complicated beast, and while V-USB library simplifies it a bit, deeper understanding is quite hard..

mohamed:

Thank you very much, I was needing a program to monitor the data from gyro and accelerometer on the computer, and making a plan for the movement of my robot, and your tutorial was the solution .

Neal:

If your using Studio 6.0 and a DRAGON programmer/debugger, here are two things I had to do to get things working.

1. You need to put the -DF_CPU=16500000 in both the compiler symbol list and the assembler flag list to get it to apply across C code and Assembly code.
2. “After” you go into debug mode, you need to disconnect the DRAGON ISP SCK line from the Attiny85 pin 7 to have the usb enumeration process to work properly. The DRAGON is supposed to tristate this line during debugging, but apparently it doesn’t. Make sure you reconnect the SCK line “before” you tell Studio 6.0 to stop debugging of you’ll have problems.

Hope this helps some of you.

Marek:

Ok. I tried everything, but i still get that error:
gcc -I ./libusb/include -L ./libusb/lib/gcc -O -Wall usbtest.c -o usbtest.exe -lusb
process_begin: CreateProcess(NULL, gcc -I ./libusb/include -L ./libusb/lib/gcc -O -Wall usbtest.c -o usbtest.exe -lusb, …) failed.
make (e=2): The system cannot find the file specified.

make.exe: *** [usbtest.exe] Error 2

I have WinAVR instaled on C:, also MinGW on C:, i didnt change Make file. Should i change something in Make file ? Maybe add som path to some files, which are needed for compilation ? i dont know…

jokkebk:

Hmm, yeah it sounds like a directory problem. You could try a little “Hello, world!” C application to test gcc working. Also, if you omit -lusb you should get errors about missing function definitions instead of files, so playing with the command line can help you pinpoint whether it’s gcc, libusb.a, or usbtest.c that the make is not finding.

The error message actually sounds like make cannot find gcc (but I’m only 40 % sure), not the libraries or source code. But I unfortunately don’t have the time to try to replicate the error. :-d Hope you get it working!

Update: I did some testing and that is exactly the error you get when you don’t have gcc installed (MinGW is the one I used for Windows compatible gcc with libraries) or its directory isn’t in your PATH setting.

Marek:

Thanks for reply.
It is finally working. I had to manage my path settings.
BTW i very like your tutorials, they are very helpful. Keep going :) Thanks again

nictex:

Hey jokkebk,

thanks for your great tutorial!
I have one question left: How can you send other data besides from char with V-USB? I want to send an integer value from my device to the PC. How do I manage this?

Thanks in advance
nictex

jokkebk:

Thanks! If you look closer to PC side usb_control_msg function call, you’ll see that it is actually sending two 16-bit integers instead of four 8-bit characters. By replacing ‘T’ + (‘E’ << 8) with a number (e.g. 15000), you can send the integer, and instead of rq->wValue.bytes[0] and bytes[1], you access it with rq->wValue.word.

For sending/receiving a 32-bit integer, you can send the lower 16 bits in wValue.word and upper 16 bits in wIndex.word.

For more data than that, you can use the buffer methods – you can easily send whatever type of data, just type cast the data pointer to character array on PC side, and type cast it back on AVR side (basic understanding of C pointers and type casting is required, I suggest some C language book for that)

nictex:

Hey jokkebk,

thanks for your fast reply!
I am a bit puzzled :D Isn’t this a way to send an integer from PC to device and not the other way round?

jokkebk:

Sorry, that is exactly how it is, seems I read your question in haste. You can use replyBuf to send ints:

((int *)replyBuf)[0] = 1234;

The above type cast tells compiler to treat the pointer as int array instead of byte, which populates 2 bytes from the start with 1234 (assuming AVR int is 16 bit). On PC side you probably need short because int is 32-bit (4 bytes)

Seb:

Incredible job, thx! Works with Code::Blocks with adding the #include and when you add the .a file (libusb-win32-bin-1.2.6.0\lib\gcc) in the linker.

Adeb:

First of all thanks a million for the tutorial. It is a great start for a beginner like me.
Just a quick question to make sure…your example is not limited to ATtiny family, right? For example if I use a ATMega168 or 328 it is going to work the same way as long as I define the pin definitions right in the usbconfig.h?

jokkebk:

Thanks! Yeah, it should work great with most 8-bit AVR:s, and definitely ATmega168 etc. :)

ngo:

Hi, I have followed the 4 part tutorial and have learned much from it.
I have a question regarding using interrupts.
Not sure if this is the place to ask the question.
I am thinking of using USART and USI interrupts to do tx and rx.
Would this interfer with the VUSB?
Thanks.

OneMoreTime:

I have been trying to figure this out for weeks now. I have a Tiny AVR Programmer and a ATtiny85 chip and was able to get the makefile and avrdude to go without error. However, when I make the circuit, USB unknown device. I cant figure it out! This tutorial is a bit hard to follow for a beginner I think. Its excellent otherwise. Can you give me some pointers? Can I program it via my Arduino Leo and Atmel Studio?

Joonas Pihlajamaa:

Sorry to hear about the problems! I don’t see any problem with using Arduino Leo, and it’s possible to build the code with Atmel Studio, but you have to add both tutorial code and V-USB code files as separate items in the project. Also, more recent Studio versions had some problem compiling V-USB.

The hardware part seems to be quite picky based on the amount of problems people have had. I haven’t yet discovered any surefire way to get it working, just trial and error with components. :(

Stan:

Your articles helped me a lot. Thanks!

Joonas Pihlajamaa:

It _might_ as USB is very timing critical, but on the other hand V-USB communications likely clear interrupts while in progress, and USART doesn’t need many clock cycles so it might not interfere with V-USB at all. It all depends on how fast the INT0 needs to be responded to when something is received over USB, don’t know the protocol internals if it needs to be “right away”, most likely not.

carlos:

Hi:

If I only want to emulate a mouse click.
is true or not I just have to put a High or Low on buttonMask during the main loop .


typedef struct{
uchar buttonMask;
char dx;
char dy;
char dWheel;
}report_t;

thanks.

ashish:

i brought the usbasp from shop. i connected usbasp to my atmega8 but i am getting this “error settin USBASP isp clock
error: programm enable :target doesnt answer 1
initialization failed rc=-1 ”
i am using extreme burner please help me.

Joonas Pihlajamaa:

Sorry cannot help you much with that one, you might want to try an electronics forum like AVRfreaks. My educated guesses for this:

1. ATmega8 is not correctly connected to ISP pins
2. Circuit gets power from two places (e.g. circuit is powered and USBasp is also set to power it) or none
3. Wront avrdude / extreme burner configuration
4. Broken USBasp

Joonas Pihlajamaa:

Hmm failed to reply to this, see my answer below after your message…

Nicola Bogdan:

It will be nice to have the same c code, wrote in java (it will be easier later to create an GUI apps etc). I struggle to communicate with the device using usb4java from http://usb4java.org/ , since now without success. I’ve searched over the net some examples, found none that use control message..

tharu:

hey, first of all thanks for the nice tutorial. i try to implement a button to modify the “Hello, usb!”

the button turns the led off, but i cant manage to edit the message on the device. any ideas? thx a lot :)

Joonas Pihlajamaa:

Unfortunately not much. You might want to try and see if the tutorial example code for sending text works by itself, and then track differences between that and your custom code

tharu:

hey, i cant get it to work. my button can turn of the led, but it does not modify the message.

my goal is to turn of the led by a button and modify the message that it can not be turned on by software.

static uchar replyBuf[16] = “Hello, USB!”; in main.c

if the button is pressed the message wich i get with “usbtext.exe out” should show me the modified message like “manual”

thanks a lot, if anyone can help me :)

Christophe:

Thank you for this tutorial which allowed me to do mine in french.
Great work.
http://www.caron.ws

Christophe:

I just made a GUI on my website with source code. I use GKT and CodeBlocks.

http://caron.ws/index.html?22GUIInterfaceGraphique.html

Joonas Pihlajamaa:

If you got the device and “usbtest.exe out” working, you are far already. :) I’d recommend first trying to change only the first letter of the message:

replyBuf[0] = ‘X’;

If that works, changing the whole string should be easy. Note that C strings are NULL-terminated, so you need to append a zero after all the letters, e.g.:

replyBuf[0] = ‘O’;
replyBuf[1] = ‘K’;
replyBuf[2] = 0; // NULL terminate

If after pressing the button, the message stays “Hello, USB!”, my first guess would be that maybe the device for some reason resets when you press the button? If you’re sure that doesn’t happen, then it sounds like something is going wrong with the buffer or string handling (always a tricky issue with C).

wolf W:

I am unable after days of trying to get my Win 8 system to recognize USBexample driver without stopping it. I have used all mentioned methods, plus rebooting with the “unsigned drivers allow” trick, no Joy! Used the INF generator but the Win 8 always strips the “VID/UID” “0x16c0/0x5dc” Off of the install and substitutes “0x0000/0x0002” for it. When Re-entering the proper “Vid/pid” It complains that the resource is already present… Even Though I got it passed it once before. Should I give up and Install Linux. Win8 will not allow it to boot from a usb drive by the way….

Vali:

on the usbasp, you need to short J3 pins to read/write slow clock chips like attiny85.

Luqman:

Hallo sir,

I am very thankful for your tutorial as I have learned much from it. I think I can grasp a bit or two of the whole coding. However I have a problem regarding the replyBuf. I tried changing the reply as I wanted to send integers later from the mcu to PC. Though the size of replyBuf is correct (which is 16), I always get some kind of smiley as the string doesn’t matter what kind of string I set as the reply. Please help me dear sir.

With best regards,
Luqman

Joonas Pihlajamaa:

Hmm, there are several ways to send integers, so the problem might be in many places. For example, if you don’t change the PC side code, but say in MCU side:

short replyBuf[8]; // should be 16 bytes

and then say replyBuf[0] = 127, you’ll get 0x00, 0x7F in your reply buffer. The first might be printed out as a smiley.

One way is to encode the numbers as hex characters and decode in PC side, but it should be perfectly possible to send integers too, just as long as you don’t print them out as characters, but treat them as integers, something like:

short buffer[128];

nBytes = usb_control_msg(handle,
USB_TYPE_VENDOR | USB_RECIP_DEVICE |
USB_ENDPOINT_IN, USB_DATA_OUT, 0, 0,
(char *)buffer, 256, 5000);

printf(“Got %d bytes, first of them %d\n”, nBytes, buffer[0]);

Not sure if it works, but it shouldn’t be hard to trial-and-error it working. :)

Luqman:

Thank you for your quick reply. I managed to send strings yesterday but having difficulty in sending integers. I tried using your suggestion. This time sending integer is possible. But the integer displayed was totally different. By sending 127, I got either 20737 or 5889 as the output. Then I tried changing the “usbMsgPtr = *replyBuf” to “usbMsgPtr = replyBuf”. There was a new output, 22846.

best regards,
Luqman

Luqman:

Hi. I’ve managed to send integers to the host and now trying to send ADC data. The problem is,I keep getting random numbers as output and it remains. Shouldn’t the value of the ADC change everytime I put call out the usbtest.exe? Thanks

Joonas Pihlajamaa:

You could first make a firmware that sends 1, 2, 3, … to the PC to make sure sending data works OK. Then switch to actual ADC values. If those are erratic, either that is the truth or then there’s a problem with ADC config. And depending on what you have connected to it, “random” values could even be the truth.

erlanapr:

Thanks for the awesome tutorials.
I’ve made my own v-usb project using atmega8535 and it works after following your tutorial. I have a question, could this v-usb based interface sends several character continously every second to the host, without command from the host? (i.e. sends analog value every 500ms or any else)
Could you please explain me how to doing that?
I have looked at many example project and I didn’t found one with that function.

Thanks for advance

Joonas Pihlajamaa:

Well, one option is to make the device to act as USB keyboard, of course that would mean you’d need to have a notepad application open and disconnect the device when using your PC. There has to be a program on PC side to receive data, so you might as well make it poll the device. There are parts of USB spec meant for file transfer and such, but even in that case, you need a receiving program.

slawek:

Hi, I suggest slight modification to case USB_DATA_OUT:
usbMsgPtr = (usbMsgPtr_t )replyBuf; //gets rid of warning ‘assignment makes integer from pointer without a cast’
return strlen((char*)replyBuf)+1; //returns real length of saved message instead of length of buffer

Bob:

Hi wolfW, I getting exactly the same error! Did you find any solutions to this (except installing Linux)?

Regards,
Bob

captain:

Hi!Joonas. thanx for the all USB tutorials with step by step explanation.I implemented this example and it works in some of the computers mostly on XP machine , but “Unknown Device” on Win7.I have changed zener diodes also,but still the same problem.can you help me in this.
The second problem i found that in the long run sometimes device loss the communication with OS.In device manager it shows the device present but no communication happen.when i unplug and replug usb it start working again.
I found there would be device reset problem or calibration in long run.
I heard there is interrupt free version of V-USB (micronucleus bootloader).Is it possible to implement this example on micronucleus bootloader(disgispark kind of device)?
Thanx for your time.

Yusuf M Matcheswala:

Hello Joonas. Very glad I stumbled upon your project page. What you describe here is the type of project I was looking for and I thing your detailed tutorial is very helpful. One question……I understand that the V_USB header files and your example code is in C. Is there something similar to V_USB but for Python instead?
Thanks and best regards,

Joonas Pihlajamaa:

On the embedded device side, 8-bit AVR MCUs cannot reasonably run Python, it would need a vastly more efficient device to do that. But if you meant PC-side, there is no V-USB dependency, I’ve used libusb (or what the name was), and most likely there is a Python interface for that as well. I’d google for “python usb control messages” or something similar.

captain:

Hi!Joonas.
Thanks for tutorial.
I implemented this example on atmega8 with 12Mhz crystal.
Can you guide me in right direction for the loss of communication between device and PC in long run.The device is not responding after few hours.It works again after re-plug or restart of PC.

David:

Hello
One problem.
When you get more data from the computer, change this line:

Case USB_DATA_IN: // receive data from the computer
datalength = (uchar) rq-> wLength.word;

to:

datalength = (int) rq-> wLength.word;

max size type uchar is 255. When wLength.word is larger than 255, do not read all the data.

0and6:

excuseme for my bad english, but i have a question, the steps for this tutorial will avail to programming the microcontroller 2313 or only for comunications with computer

Joonas Pihlajamaa:

The tutorial series covers both microcontroller USB code, and computer. For general instructions on how to program AVR microcontrollers, you might look elsewhere — this tutorial assumes you can already do that. :)