USB host (was Re: What's the real problem with wireless on the Ben?)

Werner Almesberger werner at
Wed Oct 5 08:41:40 EDT 2011

One more item: the Ingenic SoCs have the somewhat unusual feature
that many registers are implemented as set/reset flip-flops, and
to change a bit you have to write a 1 to the corresponding set or
clear register.

For example, to set pin PD09 to "1", you would write the value
1 << 9 to PDDATS. To set it back to "0", you would write 1 << 9
to PDDATC instead.

To set pins PD08 and PD09, you would write 1 << 8 | 1 << 9 to
PDDATS, etc.

USB uses differential signaling. This means that if D+ is 0, D-
must be 1, and vice versa. The exception to this rule are some
special conditions, like the end-of-packet indication, where
both are set to 0. This is called a "single-ended 0", abbreviated
as "SE0". All this is summarized in table 7-2 on page 145 of the
USB 2.0 specification.

Changing a pair of pins where one goes 0 -> 1 and the other goes
1 -> 0 requires two writes - one to PxDATS to set the pin that
should become "1", and another one to PxDATC to clear the pin
that should become "0".

This has two undesirable properties: 1) port register accesses
are slow and this therefore burns quite a few CPU cycles,
2) there will be a small delay between the pin changes.

For USB, this means that during this short delay, the bus will
be in an invalid configuration. I don't know if this will cause
trouble for low-speed USB, but I wouldn't be surprised if it did.

Here's an idea for how one could perhaps avoid this problem:

- configure the GPIO to output D+ = 1, D- = 0 (or the opposite)

- configure the MMC controller to output, on the same pins,
  D+ = 0, D- = 1.

- to send a differential "1" (D+ = 1, D- = 0), let the GPIOs
  have the pins

- to send a differential "0" (D+ = 0, D- = 1), let the MMC
  controller have the pins

A pin is switched between GPIO and a funcion, e.g., MMC, through
the "function" register. Again, this register is not set
directly, but its bits are set or cleared through a set and a
clear register, respectively.

With the above approach, the bits in the function register
both change in the same direction with switching between
differential 0 and differential 1, so only a single write is

To send a single-ended "0" (SE0) (D+ = 0, D- = 0), one would
clear the GPIO data bit for D+ and switch to GPIOs. To return
from SE0 to differential "1", one would simply set the D+ data
bit again.

I've illustrated this here:

The two flip-flops on top are for the GPIO data. In the middle
is the MMC controller. The two flip-flops at the bottom are
for selecting whether a pin is used as GPIO or for a function.
The pair of multiplexers right of the MMC controller switch to
GPIO if the corresponding PDFUN bit is 0 and to MMC if the bit
is 1.

A few detail remarks and clarifications:

- the naming convention for the port registers is
  P<port><purpose><access> where
  <port> is A, B, ...
  <purpose> is DAT for the value output on the GPIO, FUN is the
    GPIO/function selection, and so on (see the section on
    "General-Purpose I/O Ports" in the JZ4720 or JZ4740
    Programming Manual)
  <access> is S for set, C for clean, or nothing for reading
    the register's current value.

- all the MMC pins are on port D. The register names and bit
  numbers shown in the drawing are the ones that actually
  correspond to CLK and CMD.

- in the Ingenic CPU, whether a function block has access to a
  given pin is controlled on that pin. Enabling or disabling the
  function block per se is independent from its access to pins.

  This is different from the way some microcontrollers handle
  this, where enabling a function block automatically assigns a
  set of I/O pins to it.

- it should be relatively easy to make the MMC controller
  output a constant bit pattern by setting it to a low clock
  frequency and making it begin sending an MMC command. Then,
  when CMD and CLK have the desired value, stop the clock.

  All the necessary ingredients for selecting the clock and,
  erm, controlling the controller can be found in ubb-vga.c
  Note that the MMC bus clock is the 336 MHZ main clock divided
  first by 1...32 according to register MSCCDR and then by
  2^0...2^7 according to register MSC_CLKRT.

- I haven't thought this through enough to be sure whether it's
  more convenient to configure the GPIOs for a differential "1"
  and MMC for a differential "0", or the other way around. I
  think the best choice - if it makes a difference at all - will
  automatically emerge during development.

- I don't know whether switching a pin between function and GPIO
  is "smooth" or whether there can be glitches. And I also don't
  know if such a switch is, as I assume here, as fast as
  setting/clearing the port's data bit would be.

  All this would have to be verified by measurement.

- Werner

More information about the discussion mailing list