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: %sn", 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:

76 Comments or trackbacks to AVR ATtiny USB Tutorial Part 4

Marek:
February 11, 2012 at 23:35

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…..

reply

jokkebk:
February 12, 2012 at 16:07

@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.

reply

dani:
February 14, 2012 at 6:15

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?

reply

jokkebk:
February 14, 2012 at 8:02

@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…

reply

Marek:
February 14, 2012 at 22:20

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

Marek

reply

Gunner:
March 20, 2012 at 17:18

Thankyou very much..

reply

Damian:
March 29, 2012 at 12:41

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)

reply

jokkebk says:
March 29, 2012 at 16:02

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!

reply

Damian says:
March 30, 2012 at 0:21

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

reply

jokkebk says:
March 30, 2012 at 9:17

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.

reply

Damian:
March 30, 2012 at 21:12

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.

reply

jokkebk says:
April 3, 2012 at 0:10

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. :)

reply

Joseph:
April 9, 2012 at 18:51

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

Thanking You.
Regards.

reply

jokkebk says:
April 10, 2012 at 11:52

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.

reply

Joseph says:
April 10, 2012 at 12:30

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

reply

jokkebk says:
April 10, 2012 at 12:47

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!

reply

Joseph says:
April 10, 2012 at 17:28

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

erko says:
July 20, 2012 at 17:42

(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)

reply

Kyriako:
April 29, 2012 at 13:55

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.

reply

Mia:
July 4, 2012 at 9:00

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.

reply

jokkebk says:
July 4, 2012 at 10:13

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.

reply

saurabh:
July 8, 2012 at 12:10

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

reply

Rokta:
August 8, 2012 at 13:04

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?

reply

jokkebk says:
August 8, 2012 at 13:12

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.

reply

Rokta says:
August 8, 2012 at 19:49

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

reply

Marek says:
April 14, 2013 at 3:32

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…

reply

jokkebk says:
April 20, 2013 at 11:54

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 says:
April 23, 2013 at 19:32

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

starkwood:
August 13, 2012 at 0:17

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

reply

jokkebk says:
August 13, 2012 at 14:52

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.

reply

Ricky:
August 15, 2012 at 20:32

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.

reply

jokkebk says:
August 15, 2012 at 22:20

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!

reply

studyembedded:
October 23, 2012 at 18:22

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

reply

SAYED:
November 12, 2012 at 22:19

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?

reply

jokkebk says:
November 12, 2012 at 22:36

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.

reply

SAYED says:
November 25, 2012 at 1:39

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

reply

jokkebk says:
November 25, 2012 at 21:37

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. :)

reply

Metin:
November 27, 2012 at 3:18

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

reply

Mia:
December 21, 2012 at 19:23

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?

reply

jokkebk says:
December 27, 2012 at 13:54

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..

reply

Hung:
December 24, 2012 at 14:54

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.

reply

jokkebk says:
December 27, 2012 at 13:41

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. :)

reply

Hung:
December 24, 2012 at 15:01

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.

reply

mohamed:
February 9, 2013 at 18:39

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 .

reply

Neal:
February 22, 2013 at 19:35

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.

reply

nictex:
May 2, 2013 at 14:38

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

reply

jokkebk says:
May 2, 2013 at 14:48

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)

reply

nictex says:
May 2, 2013 at 15:36

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?

reply

jokkebk says:
May 7, 2013 at 9:24

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)

reply

Seb:
June 1, 2013 at 17:50

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.

reply

Adeb:
July 11, 2013 at 5:06

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?

reply

jokkebk says:
July 11, 2013 at 10:10

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

reply

ngo:
July 11, 2013 at 13:03

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.

reply

Joonas Pihlajamaa says:
December 10, 2013 at 9:50

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.

reply

OneMoreTime:
October 1, 2013 at 10:22

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?

reply

Joonas Pihlajamaa says:
October 1, 2013 at 23:13

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. :(

reply

Stan:
December 7, 2013 at 23:19

Your articles helped me a lot. Thanks!

reply

carlos:
December 16, 2013 at 6:36

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.

reply

ashish:
February 26, 2014 at 10:18

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.

reply

Joonas Pihlajamaa says:
February 26, 2014 at 10:59

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

reply

Vali says:
October 14, 2014 at 13:07

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

reply

Joonas Pihlajamaa:
February 26, 2014 at 10:58

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

reply

Nicola Bogdan:
February 28, 2014 at 17:18

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..

reply

tharu:
April 18, 2014 at 11:43

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 :)

reply

Joonas Pihlajamaa says:
April 18, 2014 at 12:07

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

reply

tharu says:
April 23, 2014 at 13:22

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 :)

reply

Joonas Pihlajamaa says:
May 28, 2014 at 11:18

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).

reply

Christophe:
April 29, 2014 at 14:23

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

reply

Christophe:
May 9, 2014 at 16:58

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

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

reply

wolf W:
July 1, 2014 at 3:47

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….

reply

Leave a Reply

Your e-mail address will not be published.


nine + 1 =

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>