Go Down

Topic: Tutorial - How to change firmware on 8u2 (Read 120989 times) previous topic - next topic

hughperman

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!

Blue_Boy

#16
Dec 03, 2010, 02:11 pm Last Edit: Dec 03, 2010, 02:34 pm by Blue_Boy Reason: 1
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?

mowcius

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

Surely you only have X,Y and Z?

Blue_Boy

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.

mowcius

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

ant.b

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

Replace
Code: [Select]
     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

Code: [Select]
     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

Code: [Select]
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:

Code: [Select]
           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.

Blue_Boy

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?

Blue_Boy

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.

Code: [Select]
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?

Blue_Boy

Quote

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.

stimmer

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.
Due VGA library - http://arduino.cc/forum/index.php/topic,150517.0.html

Blue_Boy

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.

Code: [Select]
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:

Code: [Select]
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.

stimmer

#26
Dec 07, 2010, 07:57 pm Last Edit: Dec 07, 2010, 07:58 pm by stimmer Reason: 1
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.



Due VGA library - http://arduino.cc/forum/index.php/topic,150517.0.html

ant.b

#27
Dec 07, 2010, 08:11 pm Last Edit: Dec 07, 2010, 08:13 pm by ant.b Reason: 1
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:
Code: [Select]
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

Code: [Select]
     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.

Blue_Boy

My code now looks like this:

Code: [Select]
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

Code: [Select]
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.

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


Could this be the source of my problems?

Blue_Boy

#29
Dec 08, 2010, 01:09 pm Last Edit: Dec 08, 2010, 01:09 pm by Blue_Boy Reason: 1
I'm trying to implement your code ant.
How do you send bytes out of the Arduino (atmega).

Code: [Select]
Serial.print(data, BYTE)
or just

Code: [Select]
Serial.print(data)
data ranging from 0-254?

Go Up