Tutorial - How to change firmware on 8u2

Found a solution to my problem:

http://www.avrfreaks.net/index.php?module=Freaks%20Files&func=viewFile&id=3842&showinfo=1

These drivers were signed by some generous avrfreak, and work with the Uno under Win7 64b. Happy days!

Great! I want to try this now.

Thanks so much for this! Got an Uno for the purpose of making a funky arduino accelerometerfmouse and was fretting about the lack of info on how to go about the USB HID part til I found this post. Can't wait to get choppin with it!

I've been lurking around in this thread for some time now.
I think I've wrapped my head around the general idea.
How hard would it be to add another 2 axes to the example joystick?
(axes A,B,C,D instead of only X-Y)

As far as I can see, it requires some tinkering in the Descriptors.c file.
Could any other "HID Usages" like Vx or Vbrx serve as my extra axes?

How hard would it be to add another 2 axes to the example joystick?

Surely you only have X,Y and Z?

A Playstation Dualshock styled controller has 2 thumbsticks.
So four usable axes.
I would just like to pipe 4 different sensor values into Unity using no intermediate software whatsoever, so that's why.

A Playstation Dualshock styled controller has 2 thumbsticks.
So four usable axes.
I would just like to pipe 4 different sensor values into Unity using no intermediate software whatsoever, so that's why.

Ahh I see.

PS2 has 2 more axes: Z and Rz
So Descriptors.c has to be modified:

Replace

      0x09, 0x30,          /*     Usage (X)                                      */
      0x09, 0x31,          /*     Usage (Y)                                      */
      0x15, 0x9c,          /*     Logical Minimum (-100)                         */
      0x25, 0x64,          /*     Logical Maximum (100)                          */
      0x75, 0x08,          /*     Report Size (8)                                */
      0x95, 0x02,          /*     Report Count (2)                               */

by

      0x09, 0x30,          /*     Usage (X)                                      */
      0x09, 0x31,          /*     Usage (Y)                                      */
      0x09, 0x32,          /*     Usage (Z)                                      */
      0x09, 0x35,          /*     Usage (Rz)                                      */
      0x15, 0x9c,          /*     Logical Minimum (-100)                         */
      0x25, 0x64,          /*     Logical Maximum (100)                          */
      0x75, 0x08,          /*     Report Size (8)                                */
      0x95, 0x04,          /*     Report Count (4)                               */

And change the data structure:
in Joystick.h

Replace

typedef struct
            {
                  int8_t  X; /**< Current absolute joystick X position, as a signed 8-bit integer */
                  int8_t  Y; /**< Current absolute joystick Y position, as a signed 8-bit integer */
                  uint8_t Button; /**< Bit mask of the currently pressed joystick buttons */
            } USB_JoystickReport_Data_t;

by:

            typedef struct
            {
                  int8_t  X; /**< Current absolute joystick X position, as a signed 8-bit integer */
                  int8_t  Y; /**< Current absolute joystick Y position, as a signed 8-bit integer */
                  int8_t  Z; /**< Current absolute joystick Z position, as a signed 8-bit integer */                  
                  int8_t  Rz; /**< Current absolute joystick Rz position, as a signed 8-bit integer */
                  uint8_t Button; /**< Bit mask of the currently pressed joystick buttons */
            } USB_JoystickReport_Data_t;

I think it's the only thing to modify to see the 8u2 as a 4 axes joystick.
The code that is used to manage serial communication between 8u2 and arduino has to be updated to.

Alright Ant!
Great work man, thanks!
Can you also direct me to the pages where you found this info?
The specific usage pages and hex values?

Hey,
I'm experimenting with this today.
I implemented your code. (Thanks!)
Now I have to figure out the encoding / decoding procedure.

My idea was this: send an "identification char" (a, b, c, d)
followed by the sensor data (0-255).

So in Arduino I do "Serial.println('a')" followed by "Serial.println(serialData)". That seems simple enough.

In the 82U I have this code.

bool CALLBACK_HID_Device_CreateHIDReport(USB_ClassInfo_HID_Device_t* const HIDInterfaceInfo,
                                         uint8_t* const ReportID,
                                         const uint8_t ReportType,
                                         void* ReportData,
                                         uint16_t* const ReportSize)
{
USB_JoystickReport_Data_t* JoystickReport = (USB_JoystickReport_Data_t*)ReportData;

while (Serial_IsCharReceived())
      {
      temp=Serial_RxByte();
      if (temp == "a"){JoystickReport->X  =  Serial_RxByte();}
      if (temp == "b"){JoystickReport->Y  =  Serial_RxByte();}
      if (temp == "c"){JoystickReport->Z  =  Serial_RxByte();}
      if (temp == "d"){JoystickReport->Rz =  Serial_RxByte();}
      }

*ReportSize = sizeof(USB_JoystickReport_Data_t);
      return false; 
}

But that don't work. Bummer.
Could somebody point me to why?

Comment : I have had some difficulties with Flip : I often had the error 'Address is out of range'. I don't really now why?? Does someone have an idea?

I think this might actually have to do with the size of the generated HEX file. Whenever I wrote too much code, I got over 4KB and I got this error too.

I think CALLBACK_HID_Device_CreateHIDReport has to return quickly, you don't have enough time to wait for serial data inside CALLBACK_HID_Device_CreateHIDReport. Instead you should process serial data in main, and just copy it in the callback.

Also you are assuming that the two characters will come to the serial port together - they won't. There will be a delay between the identification character and the data. However because main does other tasks (the USBTask() calls) you can't just block it while waiting for serial characters. Instead you have to code it as a state machine.

You want to use Serial.print or Serial.write rather than println as you don't want the extra newline.

The information on descriptors can be found here:
http://www.usb.org/developers/hidpage/
Unfortunately it is all very complicated and detailed. That's just the way it is.

I tried to implement the state machine you suggested Stimmer.
However, I get the "adress out of range" error in Flip.
I assume this is because I ran out of program space.
My main loop now looks like this.

int main(void)
{
      SetupHardware();
      
      LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY);
      sei();
      
      for (;;)
      {
            HID_Device_USBTask(&Joystick_HID_Interface);
            USB_USBTask();
            
            if (Serial_IsCharReceived())
                  {
                  sensorIdentification =Serial_RxByte();
                  dataReceived = true;
                  }
            
            if (Serial_IsCharReceived() && dataReceived)
                  {
                  if             (sensorIdentification == "a") {sensorA =  Serial_RxByte();}
                  else if (sensorIdentification == "b") {sensorB =  Serial_RxByte();}
                  else if (sensorIdentification == "c") {sensorC =  Serial_RxByte();}
                  else if (sensorIdentification == "d") {sensorD =  Serial_RxByte();}
                  else    {Serial_RxByte();}
                  
                  dataReceived = false;
                  }

      }
}

The "create hid report" like this:

bool CALLBACK_HID_Device_CreateHIDReport(USB_ClassInfo_HID_Device_t* const HIDInterfaceInfo,
                                         uint8_t* const ReportID,
                                         const uint8_t ReportType,
                                         void* ReportData,
                                         uint16_t* const ReportSize)
{
USB_JoystickReport_Data_t* JoystickReport = (USB_JoystickReport_Data_t*)ReportData;

JoystickReport->X  =  sensorA;
JoystickReport->Y  =  sensorB;
JoystickReport->Z  =  sensorC;
JoystickReport->Rz =  sensorD;


*ReportSize = sizeof(USB_JoystickReport_Data_t);
      return false; 
}

As it stands right now, nonfunctional.
Even when I try to only transmit the data for sensor A with the X-axis, so I'm doing a few things wrong I think.

You're on the right lines. The first if should be

if (Serial_IsCharReceived() && !dataReceived)

Serial_IsCharReceived and Serial_RxByte are inlines, so you can try to save space by only calling them once. Other ways to save space include removing the LED code, and shortening the product strings in Descriptors.c.

The memory is full as 98%. To get free space you can disable all the functions that use LEDs.

I'have emulated a joystick with uno:

I send 5 byte on serial to 8u2.

You can create this data:
uint8_t tampon;
uint8_t c;
uint8_t tempi[8];

And modify the code:

for (;;)
      {
            HID_Device_USBTask(&Joystick_HID_Interface);
            USB_USBTask();

            if (c==8)
                  c=0;
            if (Serial_IsCharReceived())
        {
                  tampon=Serial_RxByte();
                  if (tampon==0xFF)
                        c=0;
                  tempi[c]=tampon;
                  c+=1;
            }

And add that in the call back function

      JoystickReport->X=tempi[1];
      JoystickReport->Y=tempi[2];
      JoystickReport->Z=tempi[3];      
      JoystickReport->Rz=tempi[4];
      JoystickReport->Button1 =tempi[5];
      JoystickReport->Button2 =tempi[6];
      JoystickReport->Button3 =tempi[7];

The arduino has to send only bytes.
You have to use print function, not println that is sending others bytes after your data.
You can use a logic analyser to follow the data that are exchanged.

In this example, Uno has to send 0xFF as first byte (tempi[0]). However you can't send 0xFF as a data value or it will reset the c value.

My code now looks like this:

for (;;)
      {
            HID_Device_USBTask(&Joystick_HID_Interface);
            USB_USBTask();
            
            if (Serial_IsCharReceived() && !dataReceived)
                  {
                  sensorIdentification =Serial_RxByte();
                  dataReceived = true;
                  }
            
            if (Serial_IsCharReceived() && dataReceived)
                  {
                  uint8_t data = Serial_RxByte();
                  
                  if             (sensorIdentification == "a") {sensorA =  data;}
                  else if (sensorIdentification == "b") {sensorB =  data;}
                  else if (sensorIdentification == "c") {sensorC =  data;}
                  else if (sensorIdentification == "d") {sensorD =  data;}
                  
                  dataReceived = false;
                  }

      }

In the callback

USB_JoystickReport_Data_t* JoystickReport = (USB_JoystickReport_Data_t*)ReportData;

JoystickReport->X  =  sensorA;
JoystickReport->Y  =  sensorB;
JoystickReport->Z  =  sensorC;
JoystickReport->Rz =  sensorD;


*ReportSize = sizeof(USB_JoystickReport_Data_t);
      return false; 
}

But the values don't update in any way.
When I run make, I get some warnings though.

warning: comparison with string literal results in unspecified behavior
warning: comparison between pointer and integer

Could this be the source of my problems?

I'm trying to implement your code ant.
How do you send bytes out of the Arduino (atmega).

Serial.print(data, BYTE)

or just

Serial.print(data)

data ranging from 0-254?

sensorIdentification == "a" is wrong, it should be sensorIdentification == 'a' (single quotes instead of double) and the same for b,c and d.

I'm implementing (at least trying to) ant's code.
Now I'm finally getting some movement on the axes in windows again.
So at least something is getting through.
But nothing useful. I suspect it has something to do with the 0xFF start byte.

In uno's code I define something like that:

byte start_b;
byte b1; 
....

start_b=0xFF;
b1= ...
...

Serial.print(start_b);
Serial.print(b1);
....