tessel/t2-firmware

New command: digital read port (A, B)

Opened this issue · 6 comments

To make digital pin reading more efficient:

  • allowing a client to request the values of the entire port, encoded as an 8-bit unsigned int byte
  • "port value" is determined by these parameters:
    • 0 for pins that are enabled for I2C, SPI or UART use
    • 0 for pins that are input or output and currently "low"
    • 1 for pins that are input or output and currently "high"

Pins correspond to bits as:

B7 B6 B5 B4 B3 B2 B1 B0
7 6 5 4 3 2 1 0

For example, if all pins on a given port were in use as digital i/o pins and currently pin 7 is "high" and pins 0-6 are "low", then the port value would be 128:

B7 B6 B5 B4 B3 B2 B1 B0
1 0 0 0 0 0 0 0

I don't understand– can you give an example scenario for using this?

This is actually an optimization taken from the Firmata protocol, it allows client code to get the current value/state of all pins in a given port (port = set of 8 pins) at once, instead of requiring 8 separate reads with 8 corresponding responses. This is also how most IO expansion chips are designed, 8 pins = 1 (8-bit unsigned int) byte. It's a cheap (and very efficient) way to see the state of all 8 pins in a port at once.

I'm going to work on a draft patch

You could accomplish this without firmware changes by doing a batched sequence of 8 commands to read the 8 pins, which would be one round-trip instead of 8. It would still involve 16 bytes in each direction and dispatching 8 instructions, but that's negligible compared to latency and bridge overhead.

Note that with cork/uncork nonfunctional on domain sockets in the current io.js you can't guarantee that it will go out as a single batch.

I'll try both ways and see which results in the best end-to-end performance

As part of a larger effort to exploit the async IO potential of an onboard co-processor, I'm going to start working on this again, with a slight change to the plan: it should not be necessary to constantly send requests for pin values or port state. Realistically, a program should be able to send a one time request for any or all of the following:

  • send me the entire port state every N milliseconds.
  • send me the analog input value of pin P, every N milliseconds
  • send me K bytes read from I2C register at address, every N milliseconds

My original plan was to do this with macro-like sequences that execute multiple times, by adding opcodes like:

BEGIN: start recording a macro. subsequent commands until LOOP are buffered as they are executed.
LOOP: jump back to the preceding BEGIN
CANCEL: the only command legal to be sent after LOOP, makes the loop exit
PERIOD: delays until the specified time has elapsed since the start of this iteration of the loop
GPIO_WAIT: delays until the pin is high/low (to wait for interrupt / "data ready" pins)

with that, you can accomplish all of those and more.