AVR-USB I/O

General discussions about V-USB, our firmware-only implementation of a low speed USB device on Atmel's AVR microcontrollers
Rukus

AVR-USB I/O

Post by Rukus » Wed Oct 31, 2007 3:00 am

I was wondering if anyone has a example of AVR-USB using
both IN and OUT interupt endpoints?

I'm interested in sending data to the host as well as the host sending data to the ATMEGA8.

I'm attempting to learn USB communications and AVR-USB seems to be the best method.

christian
Objective Development
Objective Development
Posts: 1443
Joined: Thu Nov 09, 2006 11:46 am

Post by christian » Wed Oct 31, 2007 1:59 pm

Please check out AVR-CDC or AVR-Doper. Both use Bulk endpoints for I/O, but they are the same as interrupt endpoints except that they are polled much faster.

Rukus

Post by Rukus » Wed Oct 31, 2007 11:29 pm

Thanks Christian, I'll look it over. I've looked at several other AVR-USB projects, however I'm getting lost in the setup of the descriptors.

Rukus

Post by Rukus » Wed Oct 31, 2007 11:33 pm

What I'm attempting to do is to read some mechanical encoders to adjust a radio frequency in MS Flightsimulator via a small host application, and to then send the actual radio frequency back to the ATMEGA8 and display
the radio frequency on 7 segment led's.

I may use a I2C 7 segment display IC to drive the LED's.

I understand the simulator end, I just have to get my arms around the USB side of things.

christian
Objective Development
Objective Development
Posts: 1443
Joined: Thu Nov 09, 2006 11:46 am

Post by christian » Fri Nov 02, 2007 11:23 am

In this case I would recommend that you use an interrupt-in endpoint just to notify the host if new data is available and use control in and out transfers to read and write the actual data.

The same technology is used in RemoteSensor. When new data arrives, a one byte interrupt is sent to the host to notify it and the host reads the data with a control-in transfer. Output data can be sent with a control-out transfer at any time.

Rukus

Post by Rukus » Sat Nov 03, 2007 1:14 am

christian wrote:In this case I would recommend that you use an interrupt-in endpoint just to notify the host if new data is available and use control in and out transfers to read and write the actual data.

The same technology is used in RemoteSensor. When new data arrives, a one byte interrupt is sent to the host to notify it and the host reads the data with a control-in transfer. Output data can be sent with a control-out transfer at any time.


Thanks....I just got the ATMEGA8 running and I'm able to download programs to it. I've sent the Automator and the HIDkeys programs down to it and windows finds the devices when I plug them in.

I guess I'm on my way now to learning. The only real problems that I'm having right at the moment is defining the Discriptors and the Reports.
I guess I'll just have to plow through it and see if I can make any sense of it.

Rukus

Post by Rukus » Sat Nov 03, 2007 1:30 am

christian wrote:In this case I would recommend that you use an interrupt-in endpoint just to notify the host if new data is available and use control in and out transfers to read and write the actual data.

The same technology is used in RemoteSensor. When new data arrives, a one byte interrupt is sent to the host to notify it and the host reads the data with a control-in transfer. Output data can be sent with a control-out transfer at any time.


I have a question. I downloaded the Remote Sensor receiver program to the ATMEGA and windows finds it, but a found new hardware window pops up. Is it looking for a driver or something?

Also can I do what you suggested using a generic hid device so I don't have to write a driver for the windows side?

christian
Objective Development
Objective Development
Posts: 1443
Joined: Thu Nov 09, 2006 11:46 am

Post by christian » Sat Nov 03, 2007 9:53 am

Yes, RemoteSensor needs its own driver since it's not based on HID.

HID is somewhat limited, you can't do generic control requests. All data must be transferred in fixed size structures which must be described to the operating system by means of Report Descriptors.

In spite of the limits, HID is suitable for what you want to do. Instead of triggering just a notification with the interrupt-in endpoint, you send the payload data. Output data is still sent with a control-out transfer, but it must adhere to the structure defined in the Report Descriptor.

Constructing the Report Descriptor is not always easy. Google finds many documents which describe how to do it. I would recommend that you have a look at Automator. Although it does not use the interrupt-in endpoint, it demonstrates how arbitrary data can be encapsulated in a descriptor without too much effort.

Guest

Post by Guest » Sat Nov 03, 2007 3:23 pm

christian wrote:Yes, RemoteSensor needs its own driver since it's not based on HID.

HID is somewhat limited, you can't do generic control requests. All data must be transferred in fixed size structures which must be described to the operating system by means of Report Descriptors.

In spite of the limits, HID is suitable for what you want to do. Instead of triggering just a notification with the interrupt-in endpoint, you send the payload data. Output data is still sent with a control-out transfer, but it must adhere to the structure defined in the Report Descriptor.

Constructing the Report Descriptor is not always easy. Google finds many documents which describe how to do it. I would recommend that you have a look at Automator. Although it does not use the interrupt-in endpoint, it demonstrates how arbitrary data can be encapsulated in a descriptor without too much effort.



where is the driver for the host side of the Remote sensor project?
When the found device window pops up....what driver do I attach?

christian
Objective Development
Objective Development
Posts: 1443
Joined: Thu Nov 09, 2006 11:46 am

Post by christian » Sat Nov 03, 2007 3:57 pm

You need to install libusb-win32 and attach it to RemoteSensor's IDs. I'm not a Windows expert, so I don't have much experience with that, but the libusb-win32 package contains some instructions.

When I make software for Windows, I usually prefer HID because it saves me the extra driver.

Rukus

Post by Rukus » Sat Nov 03, 2007 4:54 pm

I've been studying Powerswitch. Correct me if I'm wrong:

avr program loops in main until it receives a USB Control message. The firmware driver calls usbFunctionSetup(uchar data[8]) and data contains
the usb command sent from powerswitch.

The usbFunctionSetup routine decides what command was sent by testing
the variable bRequest.

If it is a switchon or switchoff, it changes the output bits on its I/O, or if it
is a status request, it puts the status info into the reply buffer and returns a 2 value to the caller which indicates how many bytes to send back via the reply buffer?

If all of this is true, in my case I should be able to send a control message back to the host when one of the mechanical encoders has incremented or decremented the radio frequency. And then when the host gets it, it should be able to send a control message back to send the actual radio frequency to display via 7 segment displays?

How many bytes can I send as a control in or control out message?

This seems to do exactly what I want if I am understanding it correctly.

Thanks for your help and understanding. I'm a noob, but ya just gotta start somewhere :)

christian
Objective Development
Objective Development
Posts: 1443
Joined: Thu Nov 09, 2006 11:46 am

Post by christian » Sat Nov 03, 2007 5:05 pm

The technical description is correct. You can send control-in messages of up to 254 bytes. If your out-data fits into a setup package (one or two integers), then you can do the same as PowerSwitch and parse the data from setup. Otherwise you need a control-out transfer and implment usbFunctionWrite().

One thing is not entirely correct, though. When usbFunctionSetup() is called, you must return immediately and have reply data available. You can't wait until the encoder has incremented. However, you can poll for the encoder from the host side and return a zero increment if the encoder has not changed.

Rukus

Post by Rukus » Sat Nov 03, 2007 5:58 pm

christian wrote:The technical description is correct. You can send control-in messages of up to 254 bytes. If your out-data fits into a setup package (one or two integers), then you can do the same as PowerSwitch and parse the data from setup. Otherwise you need a control-out transfer and implment usbFunctionWrite().

One thing is not entirely correct, though. When usbFunctionSetup() is called, you must return immediately and have reply data available. You can't wait until the encoder has incremented. However, you can poll for the encoder from the host side and return a zero increment if the encoder has not changed.


Well it appears that I'm learning something :) These examples are a big help as well as your posts. I appreciate you taking the time to help me along.

Thanks again.

Rukus
Rank 1
Rank 1
Posts: 24
Joined: Tue Nov 06, 2007 10:18 am

Post by Rukus » Sat Nov 10, 2007 2:50 am

christian wrote:The technical description is correct. You can send control-in messages of up to 254 bytes. If your out-data fits into a setup package (one or two integers), then you can do the same as PowerSwitch and parse the data from setup. Otherwise you need a control-out transfer and implment usbFunctionWrite().

One thing is not entirely correct, though. When usbFunctionSetup() is called, you must return immediately and have reply data available. You can't wait until the encoder has incremented. However, you can poll for the encoder from the host side and return a zero increment if the encoder has not changed.


Christian, I've been working pretty hard trying to get this working and it appears that everything is working fine at this time. I have a routine that I wrote that reads a quadrature mechanical encoder and sends that value to the host via the HID report. This report just makes windows think that this is a joystick. The encoders just change the values of the axis information in the hid report at this time.

I'm also able to initialize these values by sending the atmega8 values via a control out message that is implemented in a form like what is being done with powerswitch. I'm able to initialize all 6 axis's to any value I want.

All of this really of no real use yet other than understanding how to send data back and forth from host ->device and device->host. I'm just about ready to implement all of the encoders to adjust radios and autopilot settings and the LCD displays for the radios and the autopilot heading, speed, altitude ect.

Durring my testing it would appear that I really don't need a interupt_in endpoint as I can send data both ways via a control message. Is this correct? If this is the case, is there a way on the host side to tell if a control message has been sent by the device? I'm using a modified version of the powerswitch program. Is there any callbacks or anything in the libusb driver that provides this type of functionality?

Anyway...thanks for all of your help.

edit: It just occured to me that I might be able to continuously poll for data from a control in via:

Code: Select all

usb_control_msg(handle, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN, PSCMD_GET, 0, 0, (char *)buffer, sizeof(buffer), 5000)


Is this true?

christian
Objective Development
Objective Development
Posts: 1443
Joined: Thu Nov 09, 2006 11:46 am

Post by christian » Sat Nov 10, 2007 7:07 pm

If you need to send data to the device, I would recommend that you also encapsulate this in reports sent to the device, so that you can stay fully compliant with HID. See the Automator project for an example.

You don't need the interrupt-in endpoint. However, the HID specification demands that one exists. The host operating system may refuse to connect to the device if there is no interrupt-in endpoint.

And finally: Yes, you can poll for control messages from the host, of course. If you declare an endpoint as interrupt-in, the operating system's USB driver does the polling for you. This is usually more efficient in terms of CPU time used.

Post Reply