====== Journal ======
[[project:journal0|Journal entries for 29 Nov 2004 -> 15 Feb 2005]]
===== Wed, 16 Feb 2005 =====
The dumb terminal here does not supprt ANSI escape sequences for bold or colour (the colour doesn't suprise me as it's monochrom). I'll have to remove the sequences for the sake of clarity. I might spend some time capturing output from the dumb terminal in hyper terminal to see what the ''clear screen'' sends..
After being on for a short while (and GoodLink(TM) being lit) an interrupt is generated, the interrupt register of the D12 has 0x80 in byte one, and 0x00 in byte two --- at this point the GoodLink(TM) indicator ceases to be lit. This indicates a suspend change. I did some probing, and it seems that the D12 suspend line is an output (which appears to default to low when not connected to anything). The data sheet claims this pin is an input, and a 4mA open drain.
There doesn't appear to be any particular time period before recieving a bus reset, or a suspend change. No illumination on the suspend pin issue.
Further tidied my code to allow a simple switch to enable / disable ANSI support in my debugging, as I've discovered that HyperTerminal is happy to interpret ANSI, allowing me the use of colour and other useful bits. Currently I'm using it to highlight interrupts as red.
I wasted some time working out the escape characters which the dumb terminal responds to, as well as reworking my code to allow a ''#define'' to enable or disable ANSI at build time. While not particularly useful, I enjoy viewing my results more, and colour makes it easier too.
{{ project:hyperterminal_goodlink_code.gif }}
Wired up my GBA using the MAX3232 and successfully got some sample ROM to talk to HyperTerminal - nothing interesting, just simple single characters back and forth (the ROM is intended for greater things than hyperterminal).
I wasn't able to makeup a compilable project from the source code (could find the ellusive ''agb.h''). I spend considerable time trawling through website looking for this header. Nothing yet.
Found a better UART demo (with seemingly more self-complete source code, but I'll look into that in due course) at [[http://www.fivemouse.com/gba/]]. I can type on the PC and it is echoed as well as output on the GBA. I'll look into compiling the code myself soon enough.
===== Thu, 17 Feb 2005 =====
I left the hardware plugged in (and on) last night before going to bed, and when I got up this morning in the gloom of English morning, I noticed that the GBA was still on! But it wasn't. :-/ Seems there is some sort of feedback from the breadboard which keeps the GBA power light half lit..
All that is required to reproduce this is to have the breadboard powered, and the GBA attached, and power it on and off again (not even on long enough for the jungle noise). It does this on both the GBA and GBA:SP - on the SP the power light goes red and occasionaly flicks green if you fiddle with the link cable.. it also emits a faint buzzing noise from the speaker! (The standard GBA unit does not, only the SP does.)
It seems that SI and SC are high and low respectivly. I disconnected SC and the problem remains. Interestingly I can still use UART fine without it. Let's see how much I can strip away - ideally I'd only have two wires left ;-)
Disconnected SD (RTS in the UART configuration) and the transmission only work in one direction now - from PC to GBA, there is nothing being sent back to the PC anymore. I guess that is to be expected. Having played with sending as much text as possible to the GBA it seems to lose a lot of the information, on account of slow screen updates. I think that in any practical situation I'm going to need to use flow control. I hope it's easy to implement on a PIC :-\. GBA still doesn't turn back on without unplugging the link.. only two wires left!
OK, disconnected each in turn. It's SI's fault. That makes sense, I've read warning about the GBA expecting this to be an output when powering on, and so not to make it uncomfortable..
I've tried configuring HyperTerminal to use flow control (Hardware, then tried XON/XOFF) and if I send bulk text much of it is still lost. I'm going to try lowering the baud rate (so it works with the dumb terminal) and then see what happens.
I modified the GBA-side code to only send an echo over RS232, and not to do anything to the screen, in the hopes of speeding up responses. This seemed to solve the slight unreliability of the demo completely - it now flawlessly echo any bulk text I send it, even at baud rate of 115200.
So, now to put it back to being a small terminal, and getting both the PIC UART and GBA UART plugs to work at the same time, then to see if the GBA can talk to the PIC..
Well the GBA talks to the PIC ok (once I removed the TTL lines from the MAX3232, I forgot that the recieve line is an output which will interfere with shortcutting a connection like that). Coded the GBA to output an ''e'' (I just typed in some hex, because my compiler was complaining about 'a' not being cast to an int or something) when you press a button. Next I want to make it output a different character for each keypress.
Right, the GBA now outputs one of the following depending on the key you press:
^ Up | %%^%% |
^ Down | v |
^ Left | < |
^ Right | > |
^ A | A |
^ B | B |
^ L | L |
^ R | R |
^ Select | s |
^ Start | S |
===== Fri, 18 Feb 2005 =====
Just finished my (short) meeting with Roger.
- I'm to stop playing with my GBA and the terminals, and get the USB working! Roger was kind enough to count the days I have until my presentation for me on his fingers. (13 days)
- **2x UART** on a PIC could be tricky and Roger isn't confident about it - he suggested it might be better to add some TTL logic to allow a PIC I/O to select the UART connection from GBA / Terminal. I'm not entirely happy with this as it could likely remove ability for the GBA to generate interrupts. Actually, come to think of it - the GBA has hardware flow control support, if I wire up the (GBA's) RTS line to a PIC I/O which has the interrupt-on-change feature I should be able to detect a GBA request to send regardless of which UART is selected. I can see problems when implementing the 'disactivates CTS' at the PIC side (to stop the GBA sending it data)... **This conflict with 1** and so won't be considered any further.
- **Schematic**, Roger likes the idea of having a very detailed schematic of the hardware, as it is something he hopes the department can reuse when they want to make use of the many spare PDIUSBD12s they now have, thanks partially to me (RS only supply them in batches of 27, and I needed a single device). Rod said he would bring in some software to help me with this (I still need to chase him up about that) and Roger approved of using some software as it forces the schematic to be complete (every pin accounted for, even if its to say 'NC'). Again, this conflicts with 1 and won't be considered further.
- Roger want's a hot-line on the progress, he wants to know about each successful step, such as "It thinks I'm a mouse", "I sent 363 through", "It sent 363 through" etc
Looks like it's firmware development for me then!
Other news today:
* Rod found a copy of the manual for the ADM 3E terminal I have been playing with, this is annoying as I'm not permitted to play with terminals until the USB portion of the project has matured. :-(
----
I was worried for a while, because the example I'm working from (Philips' D11_Mouse) seems to assume that a control endpoint OUT interrupt will be triggered during enumeration, and this has not been happening. It occured to me that speed might important, so I change the interrupt routine to be non-interactive (i.e. no longer waits for a key press before exiting), and this seemed to do it! Plenty of interrupts being triggered now (Bus reset, suspend change, another bus reset, control endpoint OUT). Along the same lines I discovered that my prompt at the start of the program also supresses further interrupts, again I presume timing is the issue here.
The double bus reset is as expected - I have read (on BeyondLogic.org) that Windows does two bus resets on any newly found device, presumably to ensure the device has had time to startup and is in a known state. At any rate, this is as expected.
Seeing as speed is important I've upped the UART baud rate to 19200 (the maximum the dumb terminal supports). I've also added debugging levels through some nifty ''#define''s, so I can change the debugging level at run-time (well, during the startup of the PIC anyways), the debugging level is defined by the state of the new DIP switches I've added to the board during init.
===== Sat, 19 Feb 2005 =====
More-or-less lost track of what I've done today. Lots. I've completely redone the code a number of times over making it much neater and more managable everytime. Encounted problem getting it to compile because of an out of ROM error due to an overly large segment size. Had to cut down on the debugging statements and seperate a few things into function that are defined as ''#SEPARATE'' to overcome this.
Implemented SETUP token handling partially, the firmware now recognises SETUP tokens and what type they are, and what they are directed at (Device, Endpoint, Interface etc). I've finished implementing ''Get_Descriptor'', it seems to work as once the Get_Descriptor request from the host is handled, the host sends a bus reset follow by a ''Set_Address'' SETUP token, which is good.
I'm testing my Set_Address code atm. I've no idea if it is working or not.. Currently it goes:
BUS RESET
BUS RESET
Get_Descriptor
Set_Address
Get_Descriptor
Set_Address
Get_Descriptor
BUS RESET
I'll need to look in to this some more.
Also executing SET_ENDPT_ENABLE seems to make the goodlink led come on, regardless of a bus reset etc...
===== Sun, 20 Feb 2005 =====
After a night's sleep I'm feeling better, and more importantly something occurred to me - the device has 2ms to change address after the CTRL_IN interrupt (status stage of the SET_ADDRESS request) before the next command arrives. I've got a delay_ms(1) in my D12_Write() function, which means it will always take longer than 2ms to set the address. So I'll need to experiment with a shorted settling time (I previously tried removing the delay altogether, and that didn't work). I'll try just a few CPU cycles.
;-) Heh, I put my CTRL_IN interrupt code for set_address in ENDPT1_IN. Oops. I've changed that and made the changes to D12_Write() anyways. The D12 datasheet says that the WR_N strobe has to last at least 20ns, in my code the set_low, set_high statements are as close as is possible, so I can only assume that it takes at least 20ns from one step to another. Doing some rough estimates:
* PIC datasheets says every (assembly) instruction takes a single cycle (except program branches which are 2)
* Running at 4MHz = 4,000,000Hz
* Each oscillator cycle takes 1/4,000,000 seconds, which is 250ns
* Each instruction takes 4 cycles (except branches, which are 8), which is 1us or 2us respectively.
* (Thanks to Christoph for pointing this out by email)
* Hence even if I was doing this in assembly, speed would still not be an issue
Well the quicker D12_Write routine isn't causing problems, but I've still had no luck with the set_address request. The "Firmware Programming Guide for PDIUSBD12" (available from Philip's semiconductors website) has flow charts for dealing with interrupts, main loops and most interestingly, most of the USB standard requests (often referred to as Chapter 9). Their flow chart for set_address seems too simple: You set the address on the D12, and //then// send a zero-length packet as acknowledgment. Everywhere else I've read up on set_address (BeyondLogic.org, USB Complete (book), and some misc) says that you have to send the zero-length packet, wait for a CTRL_IN token (which completes the status phase of the setup transaction) and //then// set your address and be able to recieve a new request within 2ms.
I'm fast running out of things to try with repesct to the set_address problem, and am beginning to consider that the problem lies else where. After analysing the logs from my debugging output I can see that the host (my laptop) correctly interpets my device's response to Get_Description. In more depth: When a new device is attached to a Windows-controlled USB hub, Windows requests the first 64 bytes of the descriptor, after recieving enough to know the length of the descriptor (8 bytes according to BeyondLogic.org) it issues a bus reset, and then issues a set_address request, followed by a get_descriptor request which requests the exact length of the descriptor (i.e. 12 bytes in my current firmware, and not the default 64 bytes). The log looks like this:
4
BUS RESET
BUS RESET
BUS RESET
Data stage direction: IN
Directed to: Device
wValue: 0x0100
wIndex: 0x0000
wLength: 0x0040
Get_Descriptor
Descriptior sent
BUS RESET
Data stage direction: OUT
Directed to: Device
wValue: 0x0001
wIndex: 0x0000
wLength: 0x0000
Set_Address
Data stage direction: IN
Directed to: Device
wValue: 0x0100
wIndex: 0x0000
wLength: 0x0012
Get_Descriptor
Descriptior sent
BUS RESET
Data stage direction: IN
Directed to: Device
wValue: 0x0100
wIndex: 0x0000
wLength: 0x0040
Get_Descriptor
Descriptior sent
BUS RESET
Data stage direction: OUT
Directed to: Device
wValue: 0x0001
wIndex: 0x0000
wLength: 0x0000
Set_Address
Data stage direction: IN
Directed to: Device
wValue: 0x0100
wIndex: 0x0000
wLength: 0x0012
Get_Descriptor
Descriptior sent
BUS RESET
Data stage direction: IN
Directed to: Device
wValue: 0x0100
wIndex: 0x0000
wLength: 0x0040
Get_Descriptor
Descriptior sent
BUS RESET
BUS RESET
The ''4'' at the beginning is the debugging level I have selected using my DIP switches on the board. The hex of a request is output before the request is dealt with, hence the value of ''wLength'' immediately above a ''Get_Descriptor'' is the requested length of the descriptor. Note it is 0x0040 (64 bytes) in the first instance and 0x0012 (18 bytes) in the second, where it follows a ''Set_Address'' request.
Up until this version of my firmware I was not sure if the second ''Get_Descriptor'' (the one following the ''Set_Address'') was being sent on the default address, or the newly issued address due to the way I was trying to only set the address after sending a zero-length packet. After taking the new approach from the firmware programming guide (which appears erronous) I am sure that the D12 has changed address.
I'd really like to have a log of all the activty at the host (i.e. my laptop) at a low enough level to see it giving up on retries and so on, but from my searching on the web I don't believe this is possible withing my budget. My current line of thinking leads me to believe that Windows doesn't like the fact that my configuration doesn't contain / mention a configuration descriptor. (It might for all I know, I just copied it from a firmware example).
I need to analyse the descriptor I've been sending and understand it.
Well that's odd!
struct DEVICE sDevice = {
sizeof( struct DEVICE), //BYTE bLength
0x01, //BYTE bDescriptorType
0x0a01, //WORD bcdUSB
...
bcdUSB (binary coded decimal for USB version) says it supports USB v10.0.1, which I somewhat doubt. BeyondLogic.org thinks this ought to be 0x0200 for USB v2.0.0 or 0x0110 for USB v1.1.0 (which is what they use in their firmware). I might try switcing to their descriptor..
I've lost all my faith in the hardware, as exectuing the D12 command SET_ADDRESS to a faulty address doesn't seem to stop it performing exactly the same operations it always does --- I would expect that it would recieve nothing except bus resets and suspect changes (which don't depend on commiunication with the host, as the rest is performed by changing the electrical properties of the D+ and D- lines for at least 10ms). I've checked the bus between the PIC and the D12, and it seems to be fine. The information in the D12's data sheet about set address/enable is extremely scarse! Is says the command is 0xD0, and that it requres writing a single byte, and provides a bitmap of the byte, showing that bit 7 represents ''enabled'' and the rest is the address. My firmware sets this to 0x0F, meaning it has a bogus address and is not enabled, yet I still get exactly the same log when I power it up.
(Hmm, what do you know, if you search for PDIUSBD12 FAQ in google, you get this page :-))
Ahh! Finally found something encouraging today! The [[http://www.semiconductors.philips.com/cgi-bin/faq/faq.pl?query=g&id=15&fid=2|Philips PDIUSBD12 FAQ]], parts of particular note:
> Q: How much current does the PDIUSBD12 consume?
>> A: During normal operation, PDIUSBD12 consumes 15 mA. In suspend mode, the PDIUSBD12 internally shuts off blocks that are not essential. This allows an operating current of 15 µA during suspend. This is particularly important for bus-powered systems as the USB Specification requires the suspend current to be 500 µA or less. See also Question 3.1. PDIUSBD12 offers bus-powered capability as it can go into deep sleep, drawing only 15 µA.
> Q: What is the difference between Set Address/Enable and SoftConnect?
>> A: The SetAddress/Enable is required to enable the SIE to respond to the USB request that is directed towards the address preset via SetAdress/Enable. Without enabling, PDIUSBD12 will not respond with the "ACK" or "NAK" token, even though the request is directed to it's preset address.
Also I noticed that at some point I wired up the EOT_N pin of the D12 incorrectly --- it is used for VBUS sensing and ought to be connected to the +5V line of the USB cabling (via resistors), I'd done everything except connect to the line to the D12, I put in in an adjacent reciprocal.. the +5V power line on my breadboard. Oops. It does seem to have changed something though, but I cannot be sure until I rewrite the firmware (as I changed the firmware and the wiring at the same time). It seems that resetting the PIC (via my push button) now resets the D12 like I always wanted it to, and the whole thing reenumerates. Also my laptop now faithfully responds with a "USB Device Not Recognized" whenever I execute the code. The problem with all this progress, is that I've disabled setting the address on in the firmware - so not even the default address is set, or enabled.
> Q: When does the system go into suspend?
>> A: The host requests that you go to suspend, or, when the host itself is in suspend, then, the USB lines are in idle mode. The electrical translation of this Idle Mode on the D+ and D- lines is a high and a low respectively. This assumes that the device has been connected to the USB bus with a pull-up resistor on the D+ line. In addition, when the device is unconnected, the device also goes to the Idle Mode if the D+ line is pulled high and the D- line is pulled low. With no activity on the USB bus, PDIUSBD12 will start to count the absence of 3 consecutive Start Of Frames (SOF) and pull the Suspend pin high. The corresponding suspend bit in the Interrupt Register is also set.
This strikes me as very odd, because the data sheet says the SUSPEND pin is an input, capable of sinking 4mA. In many ways it does make more sense from a functionality point of view.
To further reinforce this new idea of suspend being an output pin (on the D12) I also found this in the FAQs:
> Q: What is the suspend output on power up?
>> A: The suspend pin is low right after PDIUSBD12 is powered up.
> Q: What should be the width of the reset pulse PDIUSBD12?
>> A: The external reset pulse width has to be 500 µs (min.). When the reset pin is LOW, make sure the CS_N pin is in the inactive state; otherwise, the device may enter Test mode.
Now **this** annoys me, as in the data sheet they have an interfacing example where they've tied CS_N to GND. Perhaps this can explain the behaviour of my firmware.. a quick test shows that when I tie RESET_N high (which is OK as the D12 has an built-in Power-on reset circuit) the firmware behavious as I expect (that is to say doesn't do anything, as I've not enabled the address, I've only told softconnect to activate). I'd better change the firmware back to something a little more usual and see what it does.
No wait, looks like the adventure isn't over, and the ambiguous I,OD4 in the datasheet meant something different from what I thought, again.
> Q: The suspend pin is shown as an input as well as an output. Explain the behavior.
>> A: The suspend pin is a bidirectional pin. As input: When the PDIUSBD12 device is in "suspend" mode, the internal registers of the device D12 cannot be accessed. If there is a need to access the device, the microcontroller can pull the suspend pin LOW to wake up the device and then access it. This is how the suspend pin is used as an input. As an output: The PDIUSBD12 device can enter "suspend" mode as follows: The host requests the device to go into suspend, or, when the host itself is in suspend, then the USB lines are in Idle mode. The electrical translation of this Idle Mode on the D+ and D- lines is a HIGH and a LOW respectively. This assumes that the device has been connected to the USB bus with a pull-up resistor on the D+ line. In addition, when the device is unconnected, the device also goes to the Idle Mode if the D+ line is pulled HIGH and the D- line is pulled LOW. With no activity on the USB bus, PDIUSBD12 will start to count the absence of three consecutive Start Of Frames (SOF) and pull the Suspend pin HIGH. This is how the suspend pin is used as an output.
So there you have it. I guess I'll just pull the SUSPEND pin low for now, and make sure it doesn't suspend.
Things are going from bad to worse! :-\ I just got a last transaction status error of 1100, and it's not on the data sheet, it's just not there. They're missing an entry in the table of error codes, and this is it. Also the D12 is receiving a silly number of bus resets..
At least my CS_N line seems to be wired up correctly, if I set CS_N high (i.e. D12 is not selected) then the interrupt handler is unable to read from the D12 --- just nice to know that at least this works as I expect.
Bah, D12_A0 had gotten unplugged at some point, that wasted some hours of my life I can never get back. *sigh* Although I'm still not quite back to where I was this morning :-(
Right, now I am back where I was this morning, only I can use the reset button my board intead of disconnecting / reconnecting the plug like I have been previously. I noted that my desktop tries to set the device address to 0x02, while my laptop does 0x01, which is as expected, so I feel fairly confident I'm reading the right registers. Now let's see what difference coding for CS_N makes when I uncomment this set_address code...
I don't like this, the PIC seems unreliable - sometimes it output debugging info on the UART, sometimes it doesn't. Sometimes it randomly resets, sometimes it doesn't.
[About 4 hours later] :-( I removed a ''while(1);'' statement from the end of my ''main()'' function, so the PIC was resetting everytime it came out of the interrupt loop --- which was sufficiently rare (seeing as everything is interrupt driven, and that it doesn't finish enumerating - hence there is always an interrupt to be serviced) that it seemed errant. So, I'm almost back where I was this morning, I'm slowly going through my code uncommending function calls and so on, and then --- in tiny increments --- testing this new firmware on the device.
During my exasperating trail-and-erroring I tried a few different serial port loggers / terminal emulators and can say that "Advanced Serial Port Monitor" is definately worth looking into --- certainly it is more useful than HyperTerminal for my purposes, simple because it allows scrolling up (HyperTerminal corrupted the data as soon as it left the active window... go figure) and has some nice support for tagging things with time stamps and so on (which I may well use to get an idea of the timing between instrcutions).
I've completely redone the debug statements so they are all as short as possible - no more easy to understand verbose output! The log of my current firmware (which only names the interrupt fired, but doesn't handle any except a bus reset) looks like this:
0
IR=40,00 BR _SAE _SEE _SM
IR=80,00 SC
IR=c0,00 BR _SAE _SEE _SM
IR=80,00 SC
IR=c0,00 BR _SAE _SEE _SM
IR=01,00 CO
Where the leading ''0'' is the debugging level (with 0 as most verbose), ''IR'' means Interrupt Register (bytes), ''BR'' is Bus Reset, ''_SAE'' is the command Set Address Enable, similararly with Set Endpoint Enable and Set Mode, ''SC'' is Suspend Change and each newline is a seperate interrupt.
Hmm, sometimes the PIC fails to start, and tapping / pressing on it hard seems to fix this. Perhaps the ZIFF socket isn't making good contact with the breadboard?
After uncommenting all my code, this is the log:
0
IR=40,00 BR _SAE _SEE _SM
IR=80,00 SC
IR=c0,00 BR _SAE _SEE _SM
IR=80,00 SC
IR=c0,00 BR _SAE _SEE _SM
IR=01,00 CO LT=21 SE=01 DL=08 80 06 00 01 00 00 40 00 DIR=I TO=D wV=0100 wI=0000 wL=0040 SREQ Get_Descriptor
DDR DS
IR=02,00 CI LT=00
IR=40,00 BR _SAE _SEE _SM
IR=01,00 CO LT=21 SE=01 DL=08 00 05 01 00 00 00 00 00 DIR=O TO=D wV=0001 wI=0000 wL=0000 SREQ Set_Address
SAEP
IR=02,00 CI AS LT=92
IR=02,00 CI LT=c1
IR=01,00 CO LT=21 SE=01 DL=08 80 06 00 01 00 00 12 00 DIR=I TO=D wV=0100 wI=0000 wL=0012 SREQ Get_Descriptor
DDR DS
IR=02,00 CI LT=81
IR=01,00 CO LT=41
IR=40,00 BR _SAE _SEE _SM
IR=01,00 CO LT=21 SE=01 DL=08 80 06 00 01 00 00 40 00 DIR=I TO=D wV=0100 wI=0000 wL=0040 SREQ Get_Descriptor
DDR DS
IR=02,00 CI LT=00
IR=40,00 BR _SAE _SEE _SM
IR=01,00 CO LT=21 SE=01 DL=08 00 05 01 00 00 00 00 00 DIR=O TO=D wV=0001 wI=0000 wL=0000 SREQ Set_Address
SAEP
IR=02,00 CI AS LT=92
IR=02,00 CI LT=c1
IR=01,00 CO LT=21 SE=01 DL=08 80 06 00 01 00 00 12 00 DIR=I TO=D wV=0100 wI=0000 wL=0012 SREQ Get_Descriptor
DDR DS
IR=02,00 CI LT=81
IR=01,00 CO LT=41
IR=40,00 BR _SAE _SEE _SM
IR=01,00 CO LT=21 SE=01 DL=08 80 06 00 01 00 00 40 00 DIR=I TO=D wV=0100 wI=0000 wL=0040 SREQ Get_Descriptor
DDR DS
IR=02,00 CI LT=00
IR=40,00 BR _SAE _SEE _SM
IR=01,00 CO LT=21 SE=01 DL=08 00 05 01 00 00 00 00 00 DIR=O TO=D wV=0001 wI=0000 wL=0000 SREQ Set_Address
SAEP
IR=02,00 CI AS LT=92
IR=02,00 CI LT=c1
IR=01,00 CO LT=21 SE=01 DL=08 80 06 00 01 00 00 12 00 DIR=I TO=D wV=0100 wI=0000 wL=0012 SREQ Get_Descriptor
DDR DS
IR=02,00 CI LT=81
IR=01,00 CO LT=41
IR=80,00 SC
Legend:
* //Each new line represents a new interrupt//
* //All values except the debugging level are in hex, with the "0x" ommited//
* 0 = (zero) the debugging level (//zero = most verbose, 1 less so etc//)
* IR = Interrupt Registers
* BR = Bus Reset
* _SAE = D12 Set Address Enable
* _SEE = D12 Select Endpoint Enable
* _SM = D12 Set Mode
* SC = Suspend Change
* CO = Control OUT (type of interrupt)
* LT = Last Transaction Status (context of interrupt type)
* SE = Select Endpoint (read byte, context of interrupt type)
* DL = Data Length (of packet) - somtimes followed by contents of the data
* DIR = Direction of data phase (I=IN, O=OUT), for SETUP tokens
* TO = Request is for D (Device), E (Endpoint), I (Interface) or ? (Other/Unknown)
* wV = wValue (of USB Request)
* wI = wIndex (of USB Request)
* wL = wLength (of USB Request)
* SREQ = Standard (USB) Request
* Get_Descriptor / Set_Address etc = SREQ type
* DDR = Device Descriptor Requested
* DS = Descriptor Sent
* CI = Control IN (type of interrupt)
* SAEP = Set Address Enable Pending (i.e. a flag has been set, and will be serviced on the next CI interrupt)
* AS = Address Set (i.e. SAEP serviced)
Although sometimes it does sometimes get 'stuck' on ''CI'' (Control IN (interrupt))... Anyways, it is clear that the host (my laptop) makes three attempts to request the descriptor --- there is no bus reset between ''Set_Address'' and ''Get_Descriptor''.. I'll just confirm this by 'breaking' ''Set_Address'' (i.e. stopping it from actually setting the address) and see if the log is different..
:-) Seems that ''Set_Address'' works! I commented out the bit of code which changes the SET_ADDRESS_PENDING flag, so the Control Interrupt never changes the address (the current way it works is this flag is set with the new address, and on the next Control IN interrupt, the flag is checked, and address set if it is non-zero). So, I'll put it back and call it a weekend ;)
Hmm, well it seems to be back how it was, it's actually being a little inconsistent.. Ah! I got the exact same log. It's either the ZIFF socket, or my USB socket/plug are getting worn! Anyways, that's good enough for now.
===== Mon, 21 Feb 2005 =====
Reworked my debugging statements so they don't print blank lines when the debugging level ommits all statements from an interrupt.
Downloaded some tools from [[http://usbman.com]] including USBView.exe (Microsoft, 1998) which is a simple tool for viewing the descriptors of what is currently plugged in. I've nabbed the device descriptor from my mouse and am writing it to the PIC firmware now... but it didn't make a difference.
I printed out some relevant chapters from "USB Complete" (Enumeration, Descriptors and Standard Requests) and a couple of thing have occured to be with regards to my firmwares handling of the Get_Descriptor request:
* I don't believe I've taken care of sending a descriptor larger than the D12_CTRL_BUFFER_SIZE, which my descriptor is (0x12 has been fooling me into thinking it was smaller than 16 :-( )
* I don't believe the firmware properly handles being interrupted by another setup token --- Windows requests 64bytes of descriptor, and upon reading the 8th byte (the maximum packet size of endpoint 0 (Control OUT)) begins the status stage of the transfer. At the moment the send descriptor code runs as part of an interrupt, and hence cannot be interrupted.
Also I can't seem to reset the D12 as desired. Probing the INT_N line shows that if I restart the PIC when INT_N is active-low then the D12 remains in this state, and the firmware is unable to handle this.
I think I've solved this - I've added a user prompt to bring the D12 out of reset, and this does seem to work. I'll need to hammer it a bit more to be sure though.
Typical. It doesn't solve it. Thanks to it I can check the state of the RESET_N and CS_N lines, and reset is low, and CS_N is in the third state (inactive). This means that the D12's reset line doesn't do what I expect. I might just rewire my push button to break the power circuit.. that'd reset them both. [...] Hmm, broke my switch. Bah.
I'm now using a flying lead to disconnect and reconnet the power to the whole breadboard, and the D12 still enters it's weird state - the GoodLink(TM) indicator comes on, and the PIC reads the interrupt registers as 0x14,0x14 - which is unlikely, as all but bit 0 of the second byte are reserved and usually are 0 ('usually' meaning the D12 didn't light the GoodLink(TM) indicator as soon as it powered up).
Among other things, this might be the cause of some of my troubles:
> Q: Can we start accessing PDIUSBD12 immediately after the power-on reset?
>> A: After the reset, wait for 3 ms (min.) before accessing the PDIUSBD12 registers. This will allow sufficient time for the crystal clock to stabilize.
Although this doesn't address the weird state the D12 seems to get itself into... Right, I've tied RESET_N high as CS_N low.. D12 seems reliable now. I "reset" by cutting power from the whole device. Time to address the issues in Get_Descriptor handling code..
(Hmm - this page ([[project:journal]]) times out when loading - apparently parsing is taking longer than 30seconds!)
My modified Get_Descriptor handling code seems to have the same result, although the data is sent from a CTRL_IN interrupt, instead of from a deep branch of CTRL_OUT --- which means if a CTRL_OUT interrupt occurs it has priority over sending the rest of the descriptor, hence sending data can be psuedo-interrupted; "psuedo" because the data send it still part of the interrupt handler it's self, so the process can only be interrupted between induvidual packets sends. This isn't a problem //at present// because the CTRL_OUT interrupt are triggered when the //host// recieves 8-bytes, which will never be before the firmware has filled the D12 CTRL_IN buffer and validated it as fit-for-sending.
I've also added some more debugging statements to it (so I can check it is doing what I expect) and I've modified the Set_Address handler to send a null-packet before changing address - which is what I understand should be done; I had followed Philips Firmware writing guide which showed the D12_Set_Address command being executed before sending acknowledgement.
Took a very close look at the data being sent and noticed that I am trying to send 17 bytes to the D12, which is bad because the D12 only has a 16-byte buffer.
Yay! Something seems to be going well! :-) After two data-sends in response to Get_Descriptor the host now issues a new Get_Descriptor request, this time for the configuration! :-D
Changed the device descriptor to the one from the Philips D11_mouse example, and added the corresponding configuration descriptor and added a case statement to handle this. Now the host requests the device descriptor, then the configuration descriptor and then a string descriptor. The first time I tried this firmware windows reported it had found a new HID Device, and the error wasn't the usual "USB Device Not Recognised", but the new "Found New Hardware - A problem occured .." :-)
Added the configuration descriptors, double-checked my Get_Descriptor handler and tries the whole thing out! Success! Ahhh, who would have thought that after only 3.5 months of development, I'd get my device to enumerate. :-) The firmware cannot respond to string request descriptors, except the one for LANG_ID, as it is sufficiently small to fit in RAM, neither can the firmware handle 'Set_Configuration' requests, which is where the log ends. However, I am pleased to note that my firmware does the 'right' thing in these cases, and sends a STALL indicating it cannot handle/does not understand the request.
{{ project:devicemanager_usb_hid.gif }}
Of course it doesn't have a driver yet, and the descriptors are incomplete (actually it is missing some string descriptors, and not that's about it). The code which achieved this can be found [[project:usb:code:enumerated|here]]. This is just a snapshot of the code now it works, I've not made any real efforts to present it well or tidy it up.
I tried adding the other string descriptors, but the compiler said there wasn't enough RAM for this (which is believable as ''STRING1'' is 118 byes). I'll look into using the ''TABLE'' construct which allows read-only data to be stored on the ROM tomorrow, as you can't use pointers with this approach I'll have to re-write my code for sending descriptors.
===== Tue, 22 Feb 2005 =====
I've hit a "Not enough RAM" snag in my firmware - I've been copying the USB Descriptors from a Philips firmware example, and I've barely copied half to my own firmware and the compiler complains there isn't enough RAM to store them - so I'm going to have to spend some time getting familiar with the "TABLE" construct in CCS which lets me store read-only data on the Flash. Unfortunately it doesn't allow pointer access, so I'm going to have to rewrite my descriptor sending code.
I've still got plenty to do, and am by no-means stuck on what to do next: free up this RAM, implement all the descriptors from the example firmware in my own and then implement a handler for the Set_Configuration request and take it from there.
The strict timing requirements of some USB requests is making it tricky to debug, the Set_Address request has 50ms to reply with a handshake, and from there has 2ms to perform the address change - it seems to work but my log shows that after sending the null packet (the handshake) and setting the address, it immediately enounters another Control IN (to host) token, which is being 'Stalled' by my firmware.. But when I make the debugging more verbose, the request times out and it doesn't get that far!
I've fixed a pushbutton to the board, so I can momentarily disconnect the power from the whole board at a push, the button was a bit tall for my liking and kept falling over as it was stiff to push, so I've soldered it to a small board and attached this board (via flying leads) the to the main board.
I also modified the way Set_Address is handled to return a null packet before setting the address, and another after - this seems to have stopped the CTRL_IN from becoming stalled without affecting enumeration. It just seems cleaner now.
I've converted all the descriptors to constant character arrays, which gets around my "Out of RAM" compilation error, and I updated the relavent code, but this new firmware doesn't seem to start properly, it likely that an 'optimisation' I made is the cause, I'll just undo it.. Yes it was - I removed the "kick start" from my main() function, so the first interrupt from the D12 wasn't an edge (due to startup times).
It seems that my new Get_Descriptor code isn't being executed. Problem fixed, now the problem is that a new SETUP token doesn't reset the current process. Correction --- the BUS reset puts the LOAD_INDEX to 0, but doesn't set WHICH_DESCRIPTOR to 0. Fixed. Also fixed a glitch I added where the end of descriptor transmission wasn't being recognised. The current code appears to be doing exactly what the code it replaced did, so but the device doesn't enumerate, so I'm investigating the code for the other descriptors - it's very annoying not being able to use pointers and generalise the descriptor sending routine.
Found and interesting glitch in the compiler - if I used one of DEBUG #defines I get an error in MPLAB IDE that it "Failed to load [...] .cof". It seems the problem is the two statements on the same line or the length of the line in some manner, as splitting the statements onto separate lines solves this. Weird :-\.
It seems that, unlike in a ''struct'' you cannot use ''sizeof()'' to make an entry of an arrays size. This means that I have to calculate them myself and put them in, it's just a little less flexible.
More of the configuration descriptor gets sends now (first 32 of 34 bytes) before a bus reset is issued from the host. Window device manager has this to say about the 'Unknown Device':
> Windows successfully loaded the device driver for this hardware but cannot find the hardware device. (Code 41)
This doesn't mean anything obvious to me. Looking into the raw hex of the request from the host (and re-reading USB Complete Chapter 5) I see that windows is only requesting the first 9 bytes of the configuration descriptor - i.e. just the configuration bit, and not the subsections. Due to the large changes how I access the descriptors from memory this facility of my code was lost. I've just readded it, now for testing. Excellent! Back to where I was before having to change how the descriptors were compiled! :-)
Device manager again matches the screenshot in the last post. The error is:
> This device cannot start. (Code 10)
I'll look into this tomorrow (or possibly the day after, as I plan to take a break from project work tomorrow).
===== Thu, 24 Feb 2005 =====
Tidied the code a little and added some comment on reasoning for using certain methods. Discovered from the CCS manual that using two (or more) sets of UART pins is possible, by declaring a ''#use rs232()'' directive before the printf statement --- the manual recommends wrapping these in functions to increase readability rather than scattering lots of directives in the code.
Also learnt that in order to make best re-use of RAM on the PIC I ought to use many small functions --- a prime place to do this is in my ''switch()'' statements as the cases are either mutually exclusive, or only change a single variable flag. RAM usage isn't an issue at present, so I will keep the code readable for now.
Interestingly, the firmware appears to work reliable even at debugging level 0; previously verbose debugging levels seems to cause the firmware to fail to enumerate. It may be the refactoring of how Set_Address is handled that has over come this (the debugging statement is executed after the acknowledgement has been sent and the address changed). Ahh well, pity not all the output fits on the dumb terminal, I can't scroll back on it after all.
Restructured my debugging levels so that error messages (i.e. unsupported requests and such) cannot be silenced. Also lowered the level of a lot of statement in area I am confident are working and implemented properly. Set_Configuration has been implemented, although it does not affect the firmware in anyway as the global variable ''CONFIGURATION'' is currently unused --- also I need to add a global variable for the USB state, where I currently need 'Default, Addressed and Configured' as choices.
Windows is now sending a class_request for the HID, this requires reading up on a whole new topic, so I will do the above state checking/tracking first.
Added state tracking and checking, still testing it. Seems that the Set_Configuration request is conflicting with these new checks I've put in place. [...] Oops, forgot to add code to update the state to STATE_ADDRESSED when the address is set. [...] Fixed. Back to where I was, only with state checking et al.
Not too sure what is to be done next. Windows issues a ''Set_Idle'' class request, which is specific to HID devices. However, this request is optional and at the moment I have opted not to implement it, as it does not do anything meaningful in this test firmware --- however Windows is sending CTRL_IN tokens to the device, and it is being stalled. Nothing futher happens. I guess I have no choice but to implement this seemingly useless, optional, request.
It also occurs to me that I do not have a Report_Descriptor, nor is one being requested. I am certain that HID devices need report descriptors to function.
Incidently, the firmware uses 78% of the PIC16F877's ROM area, but if I make a debug-statement free build it is only 22%. :-O.
Implemented Set_Idle, and it seems to please Windows, but it doesn't appear to make any progress --- Windows does not issue any new request :-(. I've noticed in the logs that when CTRL_IN has finished transmitting descriptors CTRL_OUT recieved a non-setup token interrupt. Perhaps this is an ACK or similar. I've added some debugging statements to probe this possiblity. [...] Hmm, debugging is too slow and it missed the no-setup interrupt I want to debug, so I've reworked the debugging levels of the statements to DEBUG7, and will try again. USB Complete seems utterly convinced that the device just has to enumerate and then I can start making use of it. Something is wrong because my device doesn't properly enumerate. I think I'll switch to a different set of descriptors from a different example to explore this avenue a bit.
The non-setup tokens don't appear to hold any special data, just the contents of the buffer which are yet to be cleared. I believe these interrupts are the D12 telling us that an ACK has been recieved. While I don't have any real evidence to support this, it does appear to work and stalling this endpoint won't do anything as setup token override stalled status.
While editing the device descriptor, I noticed that I have set the device class to 0xFF, which denotes 'Vendor specific', and hence would need some specialist drivers. I would expect Windows to ask for drivers in this case, but I'll do a quick test to see if setting these to the default 0x00 helps in my enumeration problem. I've not completely copied over the descriptor from [[http://www.BeyondLogic.org|BeyondLogic.org]] yet.
Nope, doesn't seem to have helped. Also I note that my string descriptors don't show up in Device Manager anymore - they did before, and the log shows that they are being fetched. Hmm, seems that Windows acts different to my expectations - the new configurationd descriptor is 32 bytes long, which makes up exactly 2 full transactions on the PDIUSBD12, the USB specification says that if a transaction's data phase ends exactly on the end of a packet, a zero-length packet should be sent in the next tranaction to explicity state that the data ended. I was going on the assumption that the descriptor says how long it is and that was enough. I've tried implementing this null packet sending.
:-D Excellent, Windows has popped up a dialog asking for drivers. I don't have any, and BeyondLogic.org does not supply them due to being more-or-less modified versions of copyrighted code. While encouraging, this is not necessarily progress, as Windows used to load the HID class driver automatically, but still produced errors. Now I think I'll copy the descriptors from my mouse and then try to fill in the gaps using the D11_mouse example I've been using.
Hmm, plenty of small things in there which didn't seem right, but this descriptor I'm copying from my current (plugged in and working) mouse seems to make a lot more sense. For instance I believe I had the hi and lo bytes of the report descriptor length the wrong way around! Also the USB version 1.0, not 1.1 etc.
Awesome! This firmware works as much as any previous has (upto Set_Descriptor), but now Windows is issuing a Get_Descriptor request for the Report_Descriptor! :-) [...] OK, I've implemented the report descriptor, using [[http://www.USB.org|USB.org]]'s Descriptor Tool and the mouse.hid profile it came with. Windows requests this descriptor 3 times and nothing else happens. I suspect there is a mistake in the HID descriptor. I double-checked and the only thing I noticed (this time over at least) is that the HID descriptor said the report descriptor was 52 bytes long, when it is 50 --- this was caused by copying from two seperate locations. [...] That fixed it! Now it enumerates as a USB Mouse, and a lot of Enpoint_1_IN interrupts are bing triggered --- presumably this is the interrupt poll from the host. Now I need to read up on how the USB mouse class works. Oddly, the string descriptors don't seem to be being recieved again..
Didn't really get around to reading up on the HID mice, it's a bit more effort than I am willing to submit. I compared the report descriptor in the d11_mouse example with the one I got from the descriptor tool, and there is only a single differece, in the d11 example they use relative input on one of the endpoints, while the descriptor tool uses absolute. I've changed mine to match the d11 and will see if I can move my mouse by copying the d11 example some more.
It works! Plug it in and a new mouse is installed and it crawls along of its own accord! :-D I've looked into tidying the descriptors (specifically the idVendor entry) but there doesn't seem to be a 'generic' value that can be used, so for now I'll stick to Philip's semiconductors. I did find this rather nifty reference though: [[http://www.linux-usb.org/usb.ids]] which lists a lot of USB vendor IDs, as used in idVendor in the device descriptor. It also lists a lot of request types, HID usage table and similar.
Now let's see if I can get a GBA to control the direction of the mouse.
And I've done it! It is certainly not polished, but it works --- you turn on the device, after 5 seconds (enough time to enumerate etc) the GBA RS232 connection is polled with getch() at 9600 baud (all other settings are too fast for PIC, according to the CCS compiler anyway) and affects how the mouse moves on the screen. Clicking is not implemented because it was very annoying and I don't know how to map the buttons to the byte available. I just rewrote the firmware, and this one seems somewhat worse compared to the last one, the mouse jumps to the top of the screen, and to be honest there isn't much controlling coming from the GBA. Sometimes it works, sometimes it doesn't. I've made gba_getch() an uninterruptable function, simply to ensure that some data from the GBA was catpured. I'll find a more graceful way of doing this at some point. Perhaps the interrupts are serviced fast enough for this not to affect slow RS232 (assuming I remove my debugging statements, obviously)...
| {{project:devicemanager_usb_hid_mouse.gif}} | {{project:devicemanager_usb_hid_mouse_propertysheet.gif}} |
The device enumerates as a HID-Compliant device, and then instantiates itself as a HID-Mouse. The property sheet shows that the "product" is a "MeerMouse". The serial number (in the details view) is "LimitedEdition".
===== Fri, 25 Feb 2005 =====
Been playing some more with the GBA side of things, and some errors are being encountered --- ''?DR=07 S_CO''. This means an unhandled descriptor request has been made, asking for descriptor 0x07, which is the "other_speed_configuration", which is only valid in devices which support both full and high speed. The PIDUBSD12 is a full speed chip, and does not support high speed, so it would be meaningless to have the firmware support it. Currently it fails in a compliant manner.
When the debugging level is lowered I recieve a lot of ''Expecting one of 0x00, 0x01. 30!'' errors. A quick look in my firmware code reveals this is emerging from ''D12_Write()'', but interestly only parts of the two-DEBUG statement error is coming though. The source code has:
DEBUG7("Error in D12_Write(), unknown type: 0x%x!\r\n", type);
DEBUG7("Expecting one of:\r\n\t 0x%x\r\n\t0x%x\r\n", D12_COMMAND, D12_DATA);
While the output is actually:
Expecting one of:
0x01
0x00
30!
Because I am using a dumb-terminal, and because there are a great number of these errors being prouduced I cannot scroll back and check at what point this happens. It appears this was being caused by the ZIFF socket not being firmly inserted into the board. Odd.
I'm looking into how long it takes to service D12 interrupts vs how long it takes to recieve a bit from RS232 at a baud rate of 9600. Quote from [[http://francis.courtois.free.fr/jc1/serial/Basics/BitFormat.html|Data Rate, Data Bits, Parity]]
> If we're transmitting at 9600 baud, then the duration of the start bit and each subsequent bit will be about 0.104 ms. The entire character frame of eleven bits would be transmitted in about 1.146 ms.
If I the interrupt handler can complete in .1ms of less, then I wouldn't have to take any special precautions. How ever I seriously doubt that it does.
Talked to Rod and discovered that RS232 interrupts on character reception are indeed possible, found some of his old code and tested it on my firmware, and it does do what I want - triggers an interrupt on each keystroke of the dumbterminal. Now I need to change the wiring on the PIC so that the GBA is connected to the hardware USART, and the dumb terminal to the software UART.
Had issues compiling the firmware, it uses 92% ROM and 45-94% RAM, which is not good. I had to breakup the larger D12_Ctrl_In_EP() function to solve the ROM segment problem I was having. The descriptor sending code is horribly inefficient and wasteful of resources, I think I'm going to have a bash at changing the approach completely. Currently it uses lots of seperate descriptors, and for each it is necessary to have a different block of similar code. Either I can merge all the descriptors into one long constant char array (which would be hard to read) or perhaps use a function that returns a value to interleave switch statements in a single block. Neither is ideal, but such are the limitations of a PIC.
The current firmware works reliably as a mouse, and the GBA communications seems to be sufficiently short not to interfere with anything else.
The duplicated code is an issue which is bothering my quite a lot, so I might take some more "extreme" measures --- merging all descriptors into a single, less managable, character array and using some defines to mark the beginning and end of descriptors, while using the first byte of each descriptor (''bLength'') to find the length of it. Alternativly I might create a function which parses the descriptors at run time, by looking at the first and second byte of each descriptor - the first byte to work out the length -and hence beginning- of the next descriptor, and the second to check the type of descriptor. In this manner I can almost avoid having to account for different request. At present the only exception I can see if the configuration descriptor, which sends the configuration descriptor and all associated sub-descriptors as a single long series of transactions. This would make updating the firmware quite easy, which might aid in creating a "polished" feel to the project. It'd certainly be better than how I am doing it at the moment.
===== Sat, 26 Feb 2005 =====
The rewrite of the descriptor sending routines is going well, and while still not complete has reduced the necessary ROM to 67% and necessary RAM to 75%, which is quite significant; also the code is both more readable and reusable. I've still got to add the ability to select from multiple string descriptors.
The current log is below, and while the device enumerates and appears to work, I've had to disable the RDA interrupts as this was causing some weird errors indeed --- at least it seems it was this interrupt. The weird debugging output is:
Error in D12_Write(), unknown type: 0x01!
Expecting one of:
0x01
0x00
Something of interest in this log, after each ''Get_Descriptor GD(02)'' (where ''GD(02)'' means GetDescriptor (type) 2), the configuration descriptor special case executes (denoted by ''*CD(22)'', where the 22 is the new, altered, size variable) but the LOAD_LENGTH (''Ll'') remains set to 9, which is the length of the configuration descriptor alone (it should have been changed to the size of the configuration descriptor and all it's subordinate descriptors, as defined in wTotalLength, within the configuration descriptor), however a couple of lines later the same ''GD(02)'' request is handled, and the same ''*CD(22)'' exception is executed, only this second time it actually updates LOAD_LENGTH (''Ll''). The code relavent to this is included below the log. I cannot see why it works the second time as expected, but not the first.
0
IR=40,00 BR _SAE _SEE _SM
IR=80,00 SC
IR=c0,00 BR _SAE _SEE _SM
IR=80,00 SC
IR=c0,00 BR _SAE _SEE _SM
IR=03,00 CO LT=21 SE=01 DL=08 80 06 00 01 00 00 40 00 DIR=I TO=D wV=0100 wI=0000 wL=0040 SREQ Get_Descriptor GD(01) i=00(12, 01) Lo=00 Ll=12
IR=02,00 CI LT=92 DR DataLen=10 12 01 10 01 00 00 00 10 c7 05 13 01 01 00 01 02 DS
IR=02,00 CI LT=00 DR DataLen=02 03 01 DS
IR=40,00 BR _SAE _SEE _SM
IR=03,00 CO LT=21 SE=01 DL=08 00 05 00 00 00 00 00 00 DIR=O TO=D wV=0000 wI=0000 wL=0000 SREQ Set_Address SAEP
IR=02,00 CI LT=92 Z AS
IR=02,00 CI LT=c1
IR=03,00 CO LT=21 SE=01 DL=08 80 06 00 01 00 00 12 00 DIR=I TO=D wV=0100 wI=0000 wL=0012 SREQ Get_Descriptor GD(01) i=00(12, 01) Lo=00 Ll=12
IR=02,00 CI LT=92 DR DataLen=10 12 01 10 01 00 00 00 10 c7 05 13 01 01 00 01 02 DS
IR=02,00 CI LT=d2 DR DataLen=02 03 01 DS
IR=03,00 CO LT=a1 SE=01 DL=08 80 06 00 02 00 00 09 00 DIR=I TO=D wV=0200 wI=0000 wL=0009 SREQ Get_Descriptor GD(02) i=00(12, 01) i=12(09, 02) *CD(22) Lo=12 Ll=09
IR=02,00 CI LT=92 DR DataLen=09 09 02 22 00 01 01 00 a0 32 DS
IR=03,00 CO LT=a1 SE=01 DL=08 80 06 00 03 00 00 ff 00 DIR=I TO=D wV=0300 wI=0000 wL=00ff SREQ Get_Descriptor GD(03) i=00(12, 01) i=12(09, 02) i=1b(09, 04) i=24(09, 21) i=2d(07, 05) i=34(04, 03) Lo=34 Ll=04
IR=02,00 CI LT=d2 DR DataLen=04 04 03 09 04 DS
IR=03,00 CO LT=a1 SE=01 DL=08 80 06 03 03 09 04 ff 00 DIR=I TO=D wV=0303 wI=0409 wL=00ff SREQ Get_Descriptor GD(03) i=00(12, 01) i=12(09, 02) i=1b(09, 04) i=24(09, 21) i=2d(07, 05) i=34(04, 03) Lo=34 Ll=04
IR=02,00 CI LT=d2 DR DataLen=04 04 03 09 04 DS
IR=03,00 CO LT=a1 SE=01 DL=08 80 06 00 02 00 00 ff 00 DIR=I TO=D wV=0200 wI=0000 wL=00ff SREQ Get_Descriptor GD(02) i=00(12, 01) i=12(09, 02) *CD(22) Lo=12 Ll=22
IR=02,00 CI LT=d2 DR DataLen=10 09 02 22 00 01 01 00 a0 32 09 04 00 00 01 03 01 DS
IR=02,00 CI LT=d2 DR DataLen=10 02 00 09 21 10 01 00 01 22 32 00 07 05 82 03 10 DS
IR=02,00 CI LT=92 DR DataLen=02 00 ff DS
IR=03,00 CO LT=a1 SE=01 DL=08 80 06 00 03 00 00 ff 00 DIR=I TO=D wV=0300 wI=0000 wL=00ff SREQ Get_Descriptor GD(03) i=00(12, 01) i=12(09, 02) i=1b(09, 04) i=24(09, 21) i=2d(07, 05) i=34(04, 03) Lo=34 Ll=04
IR=02,00 CI LT=d2 DR DataLen=04 04 03 09 04 DS
IR=03,00 CO LT=a1 SE=01 DL=08 80 06 02 03 09 04 ff 00 DIR=I TO=D wV=0302 wI=0409 wL=00ff SREQ Get_Descriptor GD(03) i=00(12, 01) i=12(09, 02) i=1b(09, 04) i=24(09, 21) i=2d(07, 05) i=34(04, 03) Lo=34 Ll=04
IR=02,00 CI LT=d2 DR DataLen=04 04 03 09 04 DS
IR=02,00 CI LT=d2
IR=03,00 CO LT=a1 SE=01 DL=08 80 06 00 03 00 00 ff 00 DIR=I TO=D wV=0300 wI=0000 wL=00ff SREQ Get_Descriptor GD(03) i=00(12, 01) i=12(09, 02) i=1b(09, 04) i=24(09, 21) i=2d(07, 05) i=34(04, 03) Lo=34 Ll=04
IR=02,00 CI LT=92 DR DataLen=04 04 03 09 04 DS
IR=03,00 CO LT=a1 SE=01 DL=08 80 06 02 03 09 04 ff 00 DIR=I TO=D wV=0302 wI=0409 wL=00ff SREQ Get_Descriptor GD(03) i=00(12, 01) i=12(09, 02) i=1b(09, 04) i=24(09, 21) i=2d(07, 05) i=34(04, 03) Lo=34 Ll=04
IR=02,00 CI LT=d2 DR DataLen=04 04 03 09 04 DS
IR=03,00 CO LT=a1 SE=01 DL=08 80 06 00 01 00 00 12 00 DIR=I TO=D wV=0100 wI=0000 wL=0012 SREQ Get_Descriptor GD(01) i=00(12, 01) Lo=00 Ll=12
IR=02,00 CI LT=d2 DR DataLen=10 12 01 10 01 00 00 00 10 c7 05 13 01 01 00 01 02 DS
IR=02,00 CI LT=d2 DR DataLen=02 03 01 DS
IR=03,00 CO LT=a1 SE=01 DL=08 80 06 00 02 00 00 09 00 DIR=I TO=D wV=0200 wI=0000 wL=0009 SREQ Get_Descriptor GD(02) i=00(12, 01) i=12(09, 02) *CD(22) Lo=12 Ll=09
IR=02,00 CI LT=92 DR DataLen=09 09 02 22 00 01 01 00 a0 32 DS
IR=03,00 CO LT=a1 SE=01 DL=08 80 06 00 02 00 00 22 00 DIR=I TO=D wV=0200 wI=0000 wL=0022 SREQ Get_Descriptor GD(02) i=00(12, 01) i=12(09, 02) *CD(22) Lo=12 Ll=22
IR=02,00 CI LT=d2 DR DataLen=10 09 02 22 00 01 01 00 a0 32 09 04 00 00 01 03 01 DS
IR=02,00 CI LT=d2 DR DataLen=10 02 00 09 21 10 01 00 01 22 32 00 07 05 82 03 10 DS
IR=02,00 CI LT=92 DR DataLen=02 00 ff DS
IR=03,00 CO LT=a1 SE=01 DL=08 00 09 01 00 00 00 00 00 DIR=O TO=D wV=0001 wI=0000 wL=0000 SREQ Set_Configuration Z
IR=02,00 CI LT=c1
IR=03,00 CO LT=21 SE=01 DL=08 21 0a 00 00 00 00 00 00 DIR=O TO=I wV=0000 wI=0000 wL=0000 CREQ Z
IR=03,00 CO LT=21 SE=01 DL=08 81 06 00 22 00 00 72 00 DIR=I TO=I wV=2200 wI=0000 wL=0072 SREQ Get_Descriptor GD(22) i=00(12, 01) i=12(09, 02) i=1b(09, 04) i=24(09, 21) i=2d(07, 05) i=34(04, 03) i=38(1e, 03) i=56(14, 03) i=6a(1e, 03) i=88(34, 22) *RD(32) Lo=8a Ll=32
IR=02,00 CI LT=d2 DR DataLen=10 05 01 09 02 a1 01 09 01 a1 00 05 09 19 01 29 03 DS
IR=02,00 CI LT=d2 DR DataLen=10 15 00 25 01 95 03 75 01 81 02 95 01 75 05 81 01 DS
IR=02,00 CI LT=92 DR DataLen=10 05 01 09 30 09 31 15 81 25 7f 75 08 95 02 81 06 DS
IR=02,00 CI LT=d2 DR DataLen=02 c0 c0 DS
IR=03,00 CO LT=41
IR=22,00 CI LT=81 2I x01 y02 a00 b00
IR=20,00 2I x01 y02 a00 b00
IR=20,00 2I x01 y02 a00 b00
IR=20,00 2I x01 y02 a00 b00
IR=20,00 2I x01 y02 a00 b00
IR=20,00 2I x01 y02 a00 b00
IR=20,00 2I x01 y02 a00 b00
IR=20,00 2I x01 y02 a00 b00
IR=20,00 2I x01 y02 a00 b00
IR=20,00 2I x01 y02 a00 b00
IR=20,00 2I x01 y02 a00 b00
IR=20,00 2I x01 y02 a00 b00
IR=20,00 2I x01 y02 a00 b00
IR=20,00 2I x01 y02 a00 b00
.
.
And the relavent code:
void D12_Get_Descriptor(struct REQUEST *pReq){
unsigned int16 ReqDataLen, size;
unsigned char i, type;
short supported = 1;
ReqDataLen = pReq->wLength;
DEBUG0("GD(%x) ", pReq->wValue >> 8);
i = 0;
while(i < sizeof(DESCRIPTORS)-1){
// Read details from current descriptor
size = (unsigned int16) DESCRIPTORS[i];
type = DESCRIPTORS[i+1];
DEBUG0("i=%x(%x, %x) ", i, size, type);
if(type == (pReq->wValue >> 8)){ // High byte contains type
// Take care of exceptions
switch(type){
// Some descriptors do NOT contain bLength and bType bytes, these have been added
// by the author to facilitate this parsing approach. Hence we reduce the size by 2
// bytes and increase the LOAD_OFFSET by 2 bytes in such cases.
// The artificial bLength value denotes the number of bytes until the next descriptor,
// to ensure this code can 'step into' the next descriptor.
case 0x22: // Report descriptor
i = i + 2;
size = size - 2;
DEBUG0("*RD(%x) ", size);
break;
// Configuration descriptors are expected to be sent with all their subordinate
// descriptors.
case 0x02: // Configuration descriptor
size = (unsigned int16) DESCRIPTORS[i+2]; // wTotalLength low-byte
size |= (unsigned int16) DESCRIPTORS[i+3] << 8; // wTotalLength high-byte
DEBUG0("*CD(%x) ", size);
break;
}
// Don't transmit more than we need to
if( ReqDataLen > size) ReqDataLen = size;
// Setup globals for the Ctrl_IN interrupt handler
LOAD_OFFSET = i; // Start of descriptor
LOAD_LENGTH = ReqDataLen;
DEBUG0("Lo=%x Ll=%x ", LOAD_OFFSET, LOAD_LENGTH);
break; // Quite the while() loop
} else {
// Types didn't match, try the next descriptor
i = i + size;
}
}
}
Oops :-/ Closer analysis of the log shows that it is doing exactly what it is asked - the requested data length is 0x0009 in the first reuqest, so that is what is returned, in the second instance the requested data length is 0x00ff, which is trimmed to 0x0022. So it was working properly! :-)
I've added handling for string indexes (i.e. getting a specific string descriptor) and while it certainly work, it only does so at debugging level 5 and below. I'm writing a test build with //only// ''DEBUG5'' statements valid, all other DEBUGx statements have been commented out. Let's see what that does. [...] Well it didn't work straight away, didn't seem to do anything for a while. I've been getting that a lot and begin suspecting the integrity of this PIC --- after all I know for a fact that one of the pins is broken as I had to switch which line ''A0'' was connected to. Perhaps it's the reset circuit connected to the PIC? I might need to power off the board longer so the capacitor discharges properly.
Hmm, I think I may have got a major concept backwards. It seems obviously wrong now, but I thought that when the CTRL_IN endpoint recieves a token from the host it will generate an interrupt, the firmware fills it with data and the data is sent. This is clearly not the case as the interrupt actually states that it sent a NAK (because it had nothing to send). I don't know if this is related to my debugging-level dependant problems, but it certainly needs addressing. Just did a quick test, and it certainly seems to be the case. I'll have to spend some time correcting all of this now.
I seem to have solved my D12_Write() errors: I am not entirely sure what the cause was, but the solution was to remove the ''#SEPARATE'' directive from ''D12_Write()'' (and ''D12_Read()''). I can't think why passing by value to a function would corrupt data and I don't really have the time to think about it. The PIC still fails to start sometimes, which is quite worrying. Hmm, actually the D12_Write problem is not gone yet. I really doubt the quality of my PIC. I will ask for another from Rod on Monday, perhaps more than one so I can demonstrate a couple of firmwares without having to rewrite the chips.
The D12_Write() issue is still there, but becoming rare. No idea why. The PIC still fails to start quite often --- but not completely - the yellow LED does light, and that is set to happen during Init_PIC() in main(), so it does always //start// is just doesn't do anything very useful.
I'm going to try and re-enable the GBA connection via the RDA interrupt, which I presume stands for "Recieve Data Available". [...] Works well on my laptop, doesn't enumerate on my other machine - seems that my changes to Set_Address are the cause. Come to think of it the current implementation isn't exactly on spec anyways - I ought to wait for the host to send an ACK in the status stage before setting the address. Then again, surely the device does not ACK the ACK?
Weird --- this works perfectly on my laptop, but not at all on my desktop, to varying degrees! On 4 out of the 6 USB ports on my desktop, the device is passed three Get_Descriptor requests and supplementary bus resets, while on the other 2 it recieves Get_Descriptor, Bus_Reset, Set_Address, Bus_Reset, repeat. I tested this on a housemate's PC and it works fine - just like on my laptop. Werid. The USB ports on my desktop work fine with what's plugged in at the moment (and what is plugged in, does so into one of the ports which snuffs my device.)
Interesting, I suspect that my desktop will not accept this firmware partly due to it's USB controller running in a sort-of compatability mode, as there is no custom driver loaded for the USB controller hardware - it's a "Standard OpenHCD UBS Host Controller", while my laptop has an "Intel(R) 8280 1DB/DBM USB Universal Host Controller", and my housemates machine uses a branded (i.e. has special drivers loaded for it) controller; a VIA something-or-other.
Added a snapshot of the code to the site, see [[project:usb:code:HID-Mouse]].
===== Sun, 27 Feb 2005 =====
Discovered some nice (user-mode application) code on [[http://www.lvr.com/usb.htm]] for talking to HID devices. I hope to change my firmware so it can be identified by the compiled version of the code, and in order to do that I have to stop my firmware from enumerating as a mouse (as mice and keyboards are locked by the system for security reasons).
Started learning a bit about report descriptors (I'd blindly copied a standard descriptor from the Descriptor Tool).
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x02, // USAGE (Mouse)
0xa1, 0x01, // COLLECTION (Application)
0x09, 0x01, // USAGE (Pointer)
0xa1, 0x00, // COLLECTION (Physical)
0x05, 0x09, // USAGE_PAGE (Button)
0x19, 0x01, // USAGE_MINIMUM (Button 1)
0x29, 0x03, // USAGE_MAXIMUM (Button 3)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x01, // LOGICAL_MAXIMUM (1)
0x95, 0x03, // REPORT_COUNT (3)
0x75, 0x01, // REPORT_SIZE (1)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x95, 0x01, // REPORT_COUNT (1)
0x75, 0x05, // REPORT_SIZE (5)
0x81, 0x01, // INPUT (Cnst,Var,Rel)
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x30, // USAGE (X)
0x09, 0x31, // USAGE (Y)
0x15, 0x81, // LOGICAL_MINIMUM (-127)
0x25, 0x7f, // LOGICAL_MAXIMUM (127)
0x75, 0x08, // REPORT_SIZE (8)
0x95, 0x02, // REPORT_COUNT (2)
0x81, 0x06, // INPUT (Data,Var,Rel)
0xc0, // END_COLLECTION
0xc0 // END_COLLECTION
The buttons are represented by single 3 reports containing a single bit (i.e. bits 7,6,5 of the first byte of the report), followed by a single constant report, of length 5 bits (which pads the 3 button bits to make a byte), and the X and Y data are each represented by a single byte report, and uses relative positioning.
I've edited the report descriptor: changed ''0x09, 0x02, //USAGE (Mouse)'' to ''0x09, 0x04, //USAGE (Joystick)'' and the last ''0x81, 0x06, //INPUT (Data,Var,Rel)'' to ''0x81, 0x02, //INPUT (Data,Var,Abs)'', and after forcing windows to uninstall the device (it showed up as a HID-Mouse, with an error) it was enumerated as a HID-Compliant game controller, and shows up in control panel's "Game Controllers". This will be a very useful feature, as this is easier to test than something which interfers with my mouse!
I identified a small bug in my firmware. When requested strings with an index, the firmware was only using the lower nibble of the wValue (part of the host's request) in detecting an appropriate match - it ought to have been the lower //byte//, not nibble. I discovered this by using ''HidTest.exe'', which was linked to from [[http://www.lvr.com/usb.htm]].
Not had any success at creating my own HID report descriptor, or even copying anyone elses for that matter. Mouse and joystick works (gamepad too I think, I didn't check if it was different from joystick after it enumerated without error). Interestingly I read the following on the USB Implementer Forum (aka Webboard):
> The 'D12 has special support built in to it for changing the address value at the correct time.
>
> Issuing the SET ADDRESS ENABLE command (0xD0) to the 'D12 only updates a holding register...
>
> The D12 will wait until the appropriate time (right after the zero length packet representing the STATUS phase gets IN'd by the host) before it actually switches from the default address (0) to the new address.
This fixed the enumeration problem with my desktop! The PIC has been exhibiting undefined behaviour again, and has been printing gibberish to the terminal and failing to start properly numerous times. I'd consider it to be a wiring problem, but that doesn't account for printing rubbish between perfectly coherent lines; I'm more inclined to think it's a problem of overlapping interrupts, or a faulty PIC, as I have been suspecting the PIC for some time now.
This small change also seems to have fixed my low-debugging volume problems, even at debugging level 7 the device enumerates (well, it enumerates at least as often as it usually does --- if the first line of output is the debugging level followed by BR on a newline, then it works). I'm writing a debug-free version of the firmware to the PIC right now to check this a little more. [...] Yup, this works fine.
Tidied my code a little by removing the gba_getch() wrapping function and updating the rs232 directives to use streams, i.e.
#use rs232(baud = 19200, xmit = PIN_C4, rcv = PIN_C5, disable_ints)
// By using C6 and C7, we will make use of the 877's hardware USART abilities
...
//--------------------------------------------------------
// Uses compiler directives to make a wrapper for getch(),
// that specifically uses seperate pins from the normal
// debug statements
#SEPARATE
char gba_getch(){
#use rs232(baud = 9600, xmit = PIN_C6, rcv = PIN_C7, disable_ints)
return getch();
#use rs232(baud = 19200, xmit = PIN_C4, rcv = PIN_C5, disable_ints)
}
...
c = gba_getch();
became
#use rs232(baud = 9600, xmit = PIN_C6, rcv = PIN_C7, stream=GBA)
#use rs232(baud = 19200, xmit = PIN_C4, rcv = PIN_C5, stream=DEBUG)
...
c = fgetc(GBA);
:-( That introduced an annoying bug - all subsequent statements after fgetc() were using the wrong set of rs232 pins, this if all statements after fgetc() in the //source code// so it affected any functions declared after it's use as well! For this reason I've not settled on this:
#use rs232(baud = 19200, xmit = PIN_C4, rcv = PIN_C5) // Software USART (Debug)
... [rest of code] ...
#use rs232(baud = 9600, xmit = PIN_C6, rcv = PIN_C7) // Hardware USART (GBA)
c = getc();
#use rs232(baud = 19200, xmit = PIN_C4, rcv = PIN_C5) // Software USART (Debug)
Hmm, interesting [quoted from [[http://www.usb.org/phpbb/viewtopic.php?p=22158#22158|here]]]:
>> Another question is on the 0xFD command (read chip ID). There is no such command instruction listed in the PDIUSBD12 manual. Am i missing out something here?
>
> You are right that this is not documented in the PDIUSBD12 datasheet, I found out about the command on the forums here.
>
> The command is followed by 2 reads which should contain 0x12 in the first byte and 0x10 in the second (i.e. the word 0x1012)
Corrected issue with seemingly random data / sometimes unchangable data being sent to the host, as well as solving alot of nasty unpredictables with the firmware --- my REPORT_IN struct was not instantiated, it was a pointer that didn't really point to anywhere, hence memory was being corrupted and, depending on the build, strange behaviour was being observed. I now instantiate the struct in memory and these issues seems to be dormant. Also the GBA control of the joystick and buttons works as it should now, and the report data is zero on powerup. Interestingly the PIC triggers two RDA interrupts as soon as the interrupt is enabled, both characters in the buffer are null though.
I removed support for the Set_Idle HID-class request, as I made the same mistake on the HID struct and there is no point pretending to support this optional request when the firmware doesn't actually use it for anything.
The firmware seems reliable, works with my laptop at all debugging levels and even when built with no debugging at all. It does not work on my desktop when built without debugging, but works fine at all debugging levels for other builds. Pity I didn't get the custom report descriptors doing my bidding. :-(
===== Mon, 28 Feb 2005 =====
I still want to get bi-directional transfers working on my HID device, and last night something occured to me - I have a joystick (of sorts) that has a rumble feature, if I nab the report descriptor for this I ought to be able to get bi-directional transfers working soon.
Found a useful power-user feature in Windows device manager which allows you to view devices which are not connected to the PC, and uninstall them etc: [[http://support.microsoft.com/default.aspx?scid=kb;EN-US;Q315539]]
Copied the report descriptor from the joystick, using SnoopyPro --- HHD USB Monitor didn't capture the same level of detail as SnoopyPro and hence I wasn't able to extract the report descriptor using it, but snoopy pro is sufficiently simple that it caught everything and all I had to do was copy and paste the hex into my editor. I then proceeded to waste a couple of hours persuading the HID Descriptor Tool (of [[http://www.usb.org|usb.org]] that it wanted to let me input it all (so I could understand what was going on). The HID Descriptor tool is horribly unstable and kept crashing while I was manually entering / deleting entries. It's a pity it can't read in an existing HID descriptor (from, say, a C header or similar) and parse it; no you need to do the math to disecting the 6-bit numbers from the first byte and then adding the right numnber of arguments.. such a pain.
OK, my device successfully fools windows that it is a Tiger GameCube USB Box 1, but when I try to open the gamepad properties (in Control Panel's Game Controllers) it crashes, which is not suprising as I've not changed the format of the data that my device is sending out.
It seems that the custom control that the Gamecube->USB adaptor uses is issuing a Set_Report to the device, which at present my device cannot handle.
I implemented Set_Report and tested it using ''HID_Test_Application.exe'' (HIDClass.zip), from [[http://www.lvr.com/hidpage.htm|Jan Axelson's HID page]], and produced the following log:
CO LT=b2 SE=01 DL=08 DIR=O TO=I wV=0200 wI=0000 wL=0007 CREQ CREQ=SR O RID=00 I=0000 wL=0007 Z
CO LT=c1 EDl=07 RDl=07
CI LT=c1
CO LT=b2 SE=01 DL=08 DIR=O TO=I wV=0200 wI=0000 wL=0007 CREQ CREQ=SR O RID=00 I=0000 wL=0007 Z
CO LT=c1 EDl=07 RDl=08
CO LT=21 SE=01 DL=08 DIR=I TO=I wV=0100 wI=0000 wL=0008 CREQ ?CREQ=01 S_CO DIR=I TO=I wV=0100 wI=0000 wL=0008
CI LT=d2
CI LT=92 S_CI ...
CI LT=94 S_CI ...
CO LT=b2 SE=01 DL=08 DIR=O TO=I wV=0200 wI=0000 wL=0007 CREQ CREQ=SR O RID=00 I=0000 wL=0007 Z
CO LT=a1 SE=01 DL=08 DIR=I TO=I wV=0100 wI=0000 wL=0008 CREQ ?CREQ=01 S_CO DIR=I TO=I wV=0100 wI=0000 wL=0008
CI LT=d2
CI LT=92 S_CI ...
CI LT=14 S_CI ...
CO LT=b2 SE=01 DL=08 DIR=O TO=I wV=0200 wI=0000 wL=0007 CREQ CREQ=SR O RID=00 I=0000 wL=0007 Z
CO LT=a1 SE=01 DL=08 DIR=I TO=I wV=0100 wI=0000 wL=0008 CREQ ?CREQ=01 S_CO DIR=I TO=I wV=0100 wI=0000 wL=0008
CI LT=d2
CI LT=92 S_CI ...
CI LT=14 S_CI ...
CO LT=b2 SE=01 DL=08 DIR=O TO=I wV=0200 wI=0000 wL=0007 CREQ CREQ=SR O RID=00 I=0000 wL=0007 Z
CO LT=a1 SE=01 DL=08 DIR=I TO=I wV=0100 wI=0000 wL=0008 CREQ ?CREQ=01 S_CO DIR=I TO=I wV=0100 wI=0000 wL=0008
CI LT=d2
CI LT=92 S_CI ...
CI LT=14 S_CI ...
CO LT=b2 SE=01 DL=08 DIR=O TO=I wV=0200 wI=0000 wL=0007 CREQ CREQ=SR O RID=00 I=0000 wL=0007 Z
CO LT=c1 EDl=07 RDl=07
CI LT=c1
CO LT=b2 SE=01 DL=08 DIR=O TO=I wV=0200 wI=0000 wL=0007 CREQ CREQ=SR O RID=00 I=0000 wL=0007 Z
CO LT=c1 EDl=07 RDl=07
CI LT=c1
CO LT=b2 SE=01 DL=08 DIR=O TO=I wV=0200 wI=0000 wL=0007 CREQ CREQ=SR O RID=00 I=0000 wL=0007 Z
CO LT=a1 SE=01 DL=08 DIR=I TO=I wV=0100 wI=0000 wL=0008 CREQ ?CREQ=01 S_CO DIR=I TO=I wV=0100 wI=0000 wL=0008
CI LT=d2
CI LT=92 S_CI ...
CI LT=14 S_CI ...
* CREQ = Class Request
* SR = Set_Report
* RID = Report ID
* I = Interface that supports this request
* wL = wLength
* Z = Sent null packet
* EDl = Expected Data length (for this transaction)
* RDl = Recieved Data length (this transaction)
* S_CI = Stalled Control IN endpoint
Implemented Get_Report, though it seems to return null data if a Set_Report request is made at about the same time.
Modified ''Send_Report()'' to handle long reports (i.e. larger than the endpoint buffer) and did the same for ''Set_Report()'', though I've not had any real success with them. Times up, so I'm just going to leave them and put my report descriptors back to more sensible sizes and see if I can get it back to where it was.
Removed delays from ''D12_Write()'' and ''D12_Read()'', need to check things are still stable.
Right, it sends joystick data reliably (although the X/Y axis don't work as I expect, but nevermind, the buttons do) and it recieves data from HIDClass reliably and displays the data on the GBA. Moreover a non-debug build has enumerated every time (the issue was my settling time in D12_Write and D12_Read being too short.
Code snapshot is in [[project:usb:code:joystick]].
===== Wed, 2 Mar 2005 =====
While writing my [[project:presentation]] I've re-investigated BeyondLogic.org (to justify it as a reliable source of information), and thought I'd log what I found here. The author of the site, Craig Peacock, seems to work at Flinders University, Australia ([[http://www.infoeng.flinders.edu.au/people/pages/peacock_craig/]]). This was determined by looking in the about section of BeyondLogic.org and noting thanks made for something sent to Flinders Universty, with a link to the relavent department.
Produced this for my presentation:
{{project:hardware_breadboard_final_closeup_labeled.png}}
===== Fri, 4 Mar 2005 =====
Met with Roger, few things came up:
* Nothing was obviously missing from the presentation, so that's good.
* Some background USB info would be good for the report, such as when it was started, by whom and what they (originally) set out to do
* How hard would it be to convert my project to, say, a Mass Storage Device
* Comparison of USB vs Firewire, perhaps mentioning why USB isn't used in video etc (tape, no guarenteed rate --- only latency)
===== Mon, 25 Apr 2005 =====
Another meeting with Roger, likely the last scheduled meeting of this project. He reviewed my report and offered some advice:
* Add another section for USB, 2-3 pages on its general aspects in some detail - for instance low-speed, full-speed and high-speed need definiting, explaining clearly that all traffic is polled (interrupt transfers mention this in a later section of the document, but not in any depth).
* An intro / section-in-review of PICs might be in order, as very little is said about this aspect. A pros/cons or review of choices might work well --- using advertising to see what Microchip boast and critically thinking about these points might be a useful starting place if I do decide to do this; for instance of the 512 bytes of RAM, only 384 bytes were truly available for use as the others have defined purposes.
* Perhaps mentioning price/convenience factor of the project components might be a nice addition.
Also various small changes will be made, such as moving the list of figures to the front and various clarifications as commented on the hard copy.