Blog Sturntech

Archive for November, 2010

MAX3421E USB HOST Debugging: HRSLT = hrJERR (0x0D)

with 4 comments

The MAX3421E (link) is a USB Peripheral/Host Controller with SPI Interface. It contains the digital logic and analog circuitry necessary to implement a full-speed USB peripheral or a full-/low-speed host compliant to USB specification rev 2.0.

When developing with the MAX3421E, routinely checking the HRSLT codes after each USB operation is important for confirming that a given operation reached a successful completion. The MAX3421E provides the HRSL register for this purpose; specifically the HRSLT field. The following is a summary of the error codes, taken from AN3785: Max3421E Programming Guide  (link).

HRSLT codes for the MAX3421E from AN3785

Information on the exact cause of the various error codes is scarce. I recently spent several hours trying to track down why a design was encountering the 0x0D (hrJERR) code.  Several forums have postings from developers confounded by this error, with no successful resolutions discovered. It seemed important to me to share what I learned.

In my design, the MAX3421E was fully responsive via SPI and had been configured into HOST mode. I was successfully retrieving my USB test peripheral’s Device Descriptor, Configuration Descriptors, and Endpoint Descriptors. I could execute Set_Address CONTROL messages with success and everything looked fine. My DATA0/DATA1 toggles were synced properly and my transactional NAKs were at a minimum.

Then I tried to initiate a BULK_OUT transfer and encountered the hrJERR error code. Long debugging story short, I had forgotten to execute a Set_Configuration CONTROL message to the peripheral in order to actually enable the functionality of the USB peripheral. Since my firmware was attempting to drive the MAX3421E Host (and subsequently the USB peripheral) without informing the USB peripheral what to expect, the JERR error resulted from the unexpected J-State change on the D+/D- lines.

Written by sturnfie

November 23rd, 2010 at 6:38 pm

Posted in C,Design,Tip,USB

Debugging a MCP2515: Stand-alone CAN controller

without comments

The MCP2515 is a stand-alone CAN controller with SPI interface (link). This chip is able to maintain the state-machine necessary to drive/read the signals on a CAN bus.

Block Diagram of the MCP2515

I recently chose this chip to allow a micro-controller based device to communicate via a CAN bus. The SPI interface proved pretty simple; a command message is clocked into the MCP2515, followed by an address, followed by any additional data required for the particular command.

The MCP2515 has several transmit buffers, several receive buffers, several status buffers, and plenty of configuration registers to handle interfacing with the CAN bus and filtering CAN messages.

I wrote the firmware and ordered the chip. The datasheet was very complete regarding how to interface over SPI, so I didn’t expect any significant roadblocks when testing my code with the chip.

I received the chip, built a prototype unit, and gave it a whirl. The chip sent a single CAN packet and went silent. Power-cycling the prototype led to non-repeat behavior (sometimes 1 packet, sometimes none).

Ok, it is definitely a software bug. I just needed to find it. I connected a scope to an unused  I/O pin on the micro-controller. I began reading out the contents of the various MCP2515 control registers at different portions of the software. I soon discovered (via the CANCTRL and CANSTAT registers) that the device was getting pushed into LOOPBACK mode.

This was strange. The only operational modes used in my software were CONFIGURATION and NORMAL. I quickly checked the mode bits before and after each signification communication with the MCP2515 and found that the mode changed to LOOPBACK after I set the ID field of the TXBnSIDH/TXBnSIDL registers.

It turns out that I mistakenly thought the xxxxSIDL register would be at the lower address, and xxxxSIDH at the higher, of the MCP2515 register map. When writing the ID to these registers, I would write the high-order bits to the xxxxSIDH address, then decrement the xxxxSIDH address thinking this would drop me to the xxxxSIDL address.

CAN Controller register map for the MCP2515

It didn’t. Going the wrong direction in the MCP2515 register map, I was writing the xxxxSIDL value to the TXBnCTRL register. The particular xxxxSIDL value was setting the TXREQ field of this register. After setting the xxxxSIDL ID field, my code started writing the data-to-be-sent into the transmit buffer. Once TXREQ was set, the MCP2515 tries to send the data in the transmit buffer….a buffer that I was concurrently attempting to update with the data to transfer.

This causes an internal error in the MCP2515 that results in the operational mode being set to LOOPBACK. While in this mode, the transmitter and receiver buffers are directly linked internally, so no external signals are generated. Once LOOPBACK mode is entered, a request to enter NORMAL mode must be sent to resume signal transmission/reception.

Written by sturnfie

November 10th, 2010 at 1:01 pm

Posted in C,CAN,Tip,USB