view doc/CP2102-EEPROM-format @ 89:cddf60418f98

cp2102-decode-ee-desc: decode endpoint descriptors
author Mychaela Falconia <falcon@freecalypso.org>
date Wed, 27 Sep 2023 20:00:56 +0000
parents b36397a56bda
children 29bff463402e
line wrap: on
line source

The classic CP2102 single-channel USB-serial chip from Silabs (original CP2102,
not CP2102N and not CP2105) features an internal 1024-byte EEPROM, readable and
writable over USB via vendor-specific commands.  Note that it is 1024 bytes,
not bits, thus the internal EEPROM of CP2102 is 8 times bigger than that of its
direct competitor FT232R.  Compared to FTDI EEPROMs, the internal EEPROM of
CP2102 exhibits these most obvious differences:

* The all-important baud rate remapping table (the signature feature of CP2102)
  is included here;

* All USB descriptors are stored in full in the big EEPROM;

* Each of the 3 string descriptors (manufacturer, product, serial number) has a
  fixed area allocated for it, no pointer-to-string scheme like in FTDI's
  EEPROMs;

* The logical structure of CP2102 EEPROM is byte-oriented - no 16-bit words as
  elementary units.

Intel HEX format
================

Our FreeCalypso tools for working with CP2102 EEPROM are intended as a
replacement for a Python-language tool from 2014 named cp210x-program-1.0.
This original Python tool exhibits a rather peculiar format for reading and
writing raw EEPROM byte images: it is a variant of Intel HEX format with a
peculiar base address.  The size of the EEPROM is 1024 or 0x400 bytes, thus if
one were to represent an image of this EEPROM in Intel HEX with 16 bytes per
data record, the "obvious" address span would be from 0x0000 to 0x03F0.
However, the records that comprise EEPROM images written by the Python tool and
included as examples in the source tarball exhibit a different address range,
spanning from 0x3600 to 0x39F0 - the base address is 0x3600.

As there is no obvious place where this 0x3600 base address could have come
from, it is my (Mother Mychaela's) educated guess that the hex format adopted
by the author of the Python tool could have originated from Silabs' own vendor
tools, which are Windows-only and thus forbidden-ware in Themyscira temples.

Our fc-usbser-tools CP2102 EEPROM tools use the same Intel HEX format for EEPROM
images, with the same 0x3600 base address - thus we are consistent with the
Python tool which we are directly replacing, and _possibly_ consistent with
whatever sight-unseen, untouchable Windows tools might use.

EEPROM image analysis
=====================

An EEPROM image that has been read out of a CP2102 chip that appears to be
pristine (not modified after the chip left Silabs) is captured in
artifacts/CP2102-std-baud, in the variant of Intel HEX described above.

Starting from the notes included in doc/cp210x.txt in the cp210x-program-1.0
package and looking further at the EEPROM image with our own eyes, we get the
following picture of EEPROM structure:

Address 0x3600, 320 or 0x140 bytes:

	The baud rate table resides here, 32 entries of 10 bytes each.  Each
	entry has the following format:

	2 bytes: BRG reload value from Silabs AN205, big-endian
	2 bytes: timeout reload value from Silabs AN205, big-endian
	1 byte: prescaler value from Silabs AN205
	1 byte: reserved
	4 bytes: intended baud rate, little-endian

	It is not clear if the "intended baud rate" field is actually used by
	the chip for anything - it may be a sort of comment.

Address 0x3740, 0xBF bytes:

	Seems to be an unused area, all 00 bytes.

Address 0x37FF, 1 byte:

	Python cp210x package notes indicate that this byte holds the part
	number, presumably the one returned by the vendor-specific command that
	retrieves it.  This aspect remains to be tested at FreeCalypso HQ.

Address 0x3800, 4 bytes:

	USB string descriptor 0, as in USB 2.0 spec Table 9-15.

Address 0x3804, 4 bytes:

	Seems to be an unused area, all 00 bytes.  It is possible that Silabs
	may have left extra room here to allow a longer string descriptor 0,
	listing more than one language code, but it does not make sense to me
	(Mother Mychaela) to list more than one supported language when there
	is no mechanism to return different strings in response to different
	language requests.

Address 0x3808, 255 or 0xFF bytes:

	USB string descriptor for product ID string, in the full format of
	USB 2.0 spec Table 9-16.  The maximum possible length of this string is
	126 UCS-2 characters.

Address 0x3907, 128 or 0x80 bytes:

	USB string descriptor for serial number string, in the full format of
	USB 2.0 spec Table 9-16.  The maximum possible length of this string is
	63 UCS-2 characters.

Address 0x3987, 1 byte:

	Byte with value 0x02, purpose unknown.

Address 0x3988, 18 or 0x12 bytes:

	USB device descriptor, as in USB 2.0 spec Table 9-8.

Address 0x399A, 9 bytes:

	USB configuration descriptor, as in USB 2.0 spec Table 9-10.

Address 0x39A3, 9 bytes:

	USB interface descriptor, as in USB 2.0 spec Table 9-12.

Address 0x39AC, 7 bytes:

	USB endpoint descriptor, as in USB 2.0 spec Table 9-13.

Address 0x39B3, 7 bytes:

	USB endpoint descriptor, as in USB 2.0 spec Table 9-13.

Address 0x39BA, 9 bytes:

	Seems to be an unused area, all 00 bytes.

Address 0x39C3, 60 or 0x3C bytes:

	USB string descriptor for manufacturer ID string, in the full format of
	USB 2.0 spec Table 9-16.  The maximum possible length of this string is
	29 UCS-2 characters.

Address 0x39FF, 1 byte:

	0xFF is the value I find here, in the EEPROMs of CP2102-based devices
	I have on hand.  Python cp210x package notes say that this byte is lock
	status, with 0xFF meaning unlocked and 0xF0 meaning locked.