I'm using an MBED LPC1768 as a UC and I'm trying to communicate with a USB Device (a random hub) just to read the device descriptor.
I'm quite a novice in electronics.
I've connected + and – to UC 5V and GND, and D+ / D- to standards Digital/IO pins. I've also hook them up with 10K resistors to ground.
When I plug in the device, I can see D+ going up, so it means this is a high speed device.
I've try to send reset (for 20ms), then some manually encoded frames, but after sending two frames (sync / data / eop), and changing the IO pins to "input", nothings happens: bus stays in idle state (D+ up, D- down).
Here is my code:
#include "mbed.h"
#include "crc.h"
Serial pc(USBTX, USBRX);
DigitalInOut dplus(p21);
DigitalInOut dminus(p22);
void sendBits(int bits, int length);
void waitNbit(int n);
void sendPacket();
void sendEOP();
void sendReset();
void sendSync();
void setJ();
void setK();
void sendCRC(uint8_t crc);
int lastSentK; // For NRZI
int sentOneCounter; // For bit stuffing
void send0()
{
sentOneCounter = 0;
if (lastSentK) setJ();
else setK();
lastSentK = !lastSentK;
}
void send1()
{
sentOneCounter++;
waitNbit(1);
if (sentOneCounter == 6) // Bit stuffing
{
send0();
}
}
void sendCRC16(uint16_t crc)
{
// send msb first
for (int i = 0; i < 16; i++)
{
if (crc & (1 << (16 - i))) send1();
else send0();
}
}
void sendCRC(uint8_t crc)
{
// send msb first
for (int i = 0; i < 5; i++)
{
if (crc & (1 << (4 - i))) send1();
else send0();
}
}
void sendBytes(uint8_t* bytes, int length)
{
// Send lsb first
for (int i = 0; i < length; i++)
{
//printf("Sending %02X\r\n", bytes[i]);
sendBits(bytes[i], 8);
}
}
void sendBits(int bits, int length)
{
// Send lsb first
for (int i = 0; i < length; i++)
{
if (bits & 0x01) send1();
else send0();
bits = bits >> 1;
}
}
void waitNbit(int n)
{
wait_ns(n * 83); // 83 ns per byte (12MHz)
}
void sendEOP()
{
dplus = 0;
dminus = 0;
waitNbit(2);
setJ();
}
void sendReset()
{
dplus = 0;
dminus = 0;
wait_us(20 * 1000); // > 10ms
}
void sendSync()
{
// KJKJKJKK
setK();
setJ();
setK();
setJ();
setK();
setJ();
setK();
setK();
lastSentK = 1;
}
void setJ()
{
dplus = 1;
dminus = 0;
waitNbit(1);
}
void setK()
{
dplus = 0;
dminus = 1;
waitNbit(1);
}
void sendTokenPacket()
{
sendSync();
//Send packet data
sendBits(0b00101101, 8); // SETUP PID
sendBits(0, 7); // Address
sendBits(0, 4); // Endpoint
sendCRC(0x08);
sendEOP();
}
void sendSetupDataPacket()
{
sendSync();
//Send packet data
uint8_t data[] = {
0x80, // request type (direction=device to host?? type=standard recipient=device)
0x06, // bRequest GET_DESCRIPTOR
0x00, // Descriptor index
0x01, // Descriptor type (DEVICE)
0x00, // Language id
0x00, // Language id
0x12, // Length (allow device to send 18 bytes)
0x00 // ?
};
uint16_t crc = compute_crc16(data, sizeof(data));
uint8_t finalData[20];
finalData[0] = 0b11000011; // Data0 pid
memcpy(finalData + 1, data, sizeof(data));
sendBytes(finalData, sizeof(data) + 1); // Data
sendCRC16(crc);
sendEOP();
}
void listen()
{
dplus.input();
dminus.input();
uint8_t old_dplus = dplus.read();
uint8_t old_dminus = dminus.read();
//pc.printf("Status (%x ; %x).\r\n", old_dminus, old_dplus);
while (true)
{
if (dminus.read() != old_dminus || dplus.read() != old_dplus)
{
pc.printf("Change (%x->%x %x->%x).\r\n", old_dminus, dminus.read(), old_dplus, dplus.read());
old_dminus = dminus.read();
old_dplus = dplus.read();
}
waitNbit(1);
}
}
int main() {
dplus.input();
dminus.input();
pc.printf("Started\r\n");
while (true)
{
wait_us(1000 * 500); //0.5s
if (dplus.read() == 1) // Pulled high by full speed device
{
dplus.output();
dminus.output();
sendReset();
sendTokenPacket();
sendSetupDataPacket();
listen();
break;
}
}
}
What could be off, and how can I debug that?
Best Answer
To begin, your way of "manually control" serial interface is called "bit-banging". FYI.
Then, you need to do quite a bit more than what you described.
First, you have to start a CONTINUOUS stream of frame packets on 1 ms interval, with incremented frame counter.
Second, to get any response from a USB device, you need to send a valid USB request. The first request is usually the "GET_DESCRIPTOR" from default control pipe (address 0 endpoint 0).
This would be your first challenge.
So far I have not heard of any bit-bang implementation of full-speed (12 mbps) USB protocol on ARM-level processors. There are LS implementations though.
The only successful bit-banging implementation of 12-mbps USB I know of is on Parallax/Propeller MCU, which is a symmetrical 8-core 32-bit processor running at 80 MHz, with special IO access features.
No, it means that it could be either FS or HS device, depending on whether the device asserts Chirp-K during USB bus reset. FYI.