I know I've been silent lately... been distracted by a couple other
highly urgent projects.
I've been merging code into the "hardwareAbstraction" branch and testing
with Pduino. I should be making a first commit pretty soon. I've been
running into a few thorny issues, which I believe are potential problems
in the trunk as well.
The first is possible danger of using 8 bit port writes and also
supporting Servo objects. When Firmata receives an 8-bit output
message, if it writes to those 8 pins and any of the 8 are in servo mode
instead of output mode, those pins will be overwritten with wrong state
until the next time the Servo library interrupt updates the pins.
Previously the only danger was writing 1s to pins in analog mode
(turning on the pullup resistors), and in the trunk there is a loop
which zeros out any pins not in output mode on the analog port. But
with servo support, it's not safe to write either a 1 or a 0. Nearly
all pins can potentially be configured in servo mode.
The easy solution is a loop that calls digitalWrite, after checking if
the pin is output mode. The more optimal but complex solution would be
to compose a mask of which pins are writable, either as needed in the
output callback or ahead of time in the pinmode callback. I'm
experimenting with both approaches. Neither is as simple as the old way
of just writing directly to the port, but with servo (and possibly other
software implemented modes in the future), it just isn't safe to write
directly to the port.
The second issue is pins 14 and 15 on standard Arduino. Most of the
code in trunk treats these two pins as undefined (or "14,15 are disabled
for the crystal"). However, there are a number of places in
StandardFirmata that make me wonder if using the analog pins as digital,
especially using some as analog, some as digital input and some as
digital output has ever really worked well?
My biggest question, and the one thing I would appreciate most if you
have time to answer only 1 question from this lengthy email, is if my
understanding of Firmata's correspondence between digital pin and port
numbers is correct. From the protocol page:
* up to 16 analog pins
* up to 128 digital pins (16 * 8-bit ports)
* digital I/O message 0x90 port LSB(bits 0-6) MSB(bits 7-13)
* report digital port 0xD0 port disable/enable(0/1) - n/a -
* set pin mode(I/O) 0xF4 pin # (0-127) pin state(0=in)
From the protocol documentation, it seem like the 4 bit port number
always maps to exactly 8 of the pins. So port 0 would be pins 0 to 7,
port 1 would be pins 8 to 15, port 2 would be pins 16 to 23, and so on.
StandardFirmata in trunk seems to follow this convention everywhere,
except in the pinmode callback. There it attempts to map pins 14 to 21
onto port 2, instead of pins 16 to 23.
So far, I tried to follow very faithfully leaving 14 and 15 undefined in
the hardware abstraction layer, following my understanding of the
protocol. Maybe I've misunderstood something? Or maybe the handling of
these pins as never been perfectly clear?
There are other places in the code that make me question if using the
analog pins in other modes has ever really worked well (eg, turning on
reporting of digital inputs for that port disables all analog reporting,
regardless of which pins are configured as analog or digital input or
output). The changes I'm making in the hardwareAbstraction branch
should solve all such issues, but I need to be clear if I'm following
the protocol correctly.
A third issue is handling the millis 32 bit rollover. The analog
sampling interval calc in most of the examples, I believe, could get
"stuck". I'm planning to change these to a known safe approach in the
I realize, and I'm sorry, this is a whole lot more complexity than "just
port it to other boards". My first attempt applied the hardware
abstraction to other boards and left all the original code intact. That
is still an option, but I'm trying to merge all the code nicely, so the
same hardware abstraction model is used with Arudino, yet preserves the
Hans-Christoph Steiner wrote:
> Hey Paul,
> I'm partial to having separate messages for querying the hardware
> capabilities (16 analogIns, 48 digitalIns, 14 PWMS, etc.) versus the
> current configuration (pin0=output, pin1=PWM, pin2=analog, etc.). Off
> the top of my head, I think that the hardware capabilities should be
> reported as one big report since it doesn't change. This is what USB
> HID does in the initial negotiation.
> Then the config query makes sense to do per-pin, since you probably
> just want to know what a certain pin is doing, and might query it more
> than once.
> Feel free to add your proposal to that wiki page, that's what its
> there for. Hopefully we can get Shigeru and Massimo to respond, since
> they have proposed querying ideas as well. I don't have a strong
> sense of how it should work, but I know USB HID well, so I can talk
> about how that works, for better or worse.
> On Jan 14, 2010, at 10:50 AM, Paul Stoffregen wrote:
>> Looking at the protocol specs, I can see there's already a few
>> I would like to put forth a proposal that (hopefully) accomplishes
>> all of these. Here goes.
>> A host that wishes to learn the capabilities and configuration of the
>> pins on a Firmata device may send pinFeatures query requests. Each
>> request queries a single pin. To discover all pins, the host must
>> send one request per pin.
>> /* pinFeatures query request
>> * ------------------------------
>> * 0 START_SYSEX (0xF0)
>> * 1 pinFeatures (0x??)
>> * 2 pinNumber
>> * 3 END_SYSEX (0xF7)
>> A device shall respond with a pinFeatures data reply. All replies
>> must contain at least 3 data bytes (plus sysex start/end). Bytes 1
>> and 2 echo the request parameters. Byte 3 must indicate the mode
>> that is currently in use. If the pin does not exist, 255 is
>> returned. The number of pins may be inferred by repeated queries at
>> sequential pin numbers until a 255 code is returned.
>> For each mode the pin is capable of using, a pair of bytes will
>> indicate the index byte (as used with "set pin mode", command 0xF4)
>> used to configure that mode, and a byte indicating the resolution
>> supported by that mode, or other mode-specific descriptive
>> information. If resolution does not apply, 0 is sent. The number of
>> modes the pin supports shall be inferred by the length of the message.
>> /* pinFeatures data reply
>> * ------------------------------
>> * 0 START_SYSEX (0xF0)
>> * 1 pinFeatures(0x??)
>> * 2 pinNumber
>> * 3 currentlyConfiguredMode (255 if pin does not exist)
>> * 4 index of 0th available pin mode
>> * 5 resolution of 0th available mode (0 if resolution doesn't apply)
>> * 6 index of 1st available pin mode
>> * 7 resolution of 1th available mode (0 if resolution doesn't apply)
>> * ....
>> * n END_SYSEX (0xF7)
>> It is legal for a pin to exist yet not support any modes, in which
>> case the host should ignore byte 3 and should present such a pin to
>> the user as inactive or invisible or disabled (eg, a gray,
>> unresponsive GUI widget). This case may apply to pins 0 and 1 on
>> most Arduino boards, because those pins are in use for serial
>> communication and therefore can not implement any usable pin modes
>> for Firmata.
>> The main difference in this proposal is a small, single pin message.
>> As Firmata is extended with more capabilities and boards like the
>> Arduino Mega have large numbers of pins, sending one giant message
>> that attempts to describe all pins could tie up the serial line for
>> quite some time. Using the existing API, it could also require a
>> very large memory buffer in the device to compose the entire
>> message. Going to one pin at a time makes for simpler and smaller
>> code in the device and shorter, bandwidth/latency friendly messages
>> on the wire, at the expense of a loop to read them all on the host.
>> The other big difference is expressing pin modes as the same bytes
>> that are used to set them with the 0xF4 message. This gives the best
>> extensibility for future features. The bitmask approach, shown as
>> only 8 bits per pin, would be limited to only 8 pin modes, and
>> Firmata.h already has 7 defined. Unlike a bitmask, bandwidth only
>> needs to be used for modes that actually are implemented. This
>> proposal also moved the resolution info from a global scope to a
>> per-pin scope, which could in the future support devices with
>> different resolution depending on the pin.
>> I'm really thinking seriously about throwing together a stand-alone
>> GUI app. To work with any board, it really must have the ability to
>> discover this information.
>> Please, if anyone has opinions, comment now!
>> Paul Stoffregen wrote:
>>> I'd like to ask about the possibility of adding a couple more
>>> Firmata messages... if these don't already exist and I'm just not
>>> aware of them.
>>> The first would be a sysex message to allow more than 16 analog
>>> outputs. More than 16 is a real possibility. For example, can
>>> Arduino Mega support 48 servos, but only 14 can be used (pins 0 and
>>> 1 are reserved for communications) because the analog write message
>>> can only address 0 to 15.
>>> The second would be a query for pin configuration. There are a lot
>>> of ways this could work. One simple one might be a per-pin query,
>>> where a sysex message is returned that gives the current
>>> configuration of the requested pin and a list of all the modes it
>>> supports. A Firmata host could begin at pin 0 and learn the current
>>> setting of every pin and which pins support what features. If
>>> there's some well defined response for queries beyond the maximum
>>> pin number, it could also learn how many pins are present.
>>> I'm imagining building a GUI-based app (probably in C++ with
>>> wxWidgets or FLTK) and I would need some way to know how many pins
>>> the Firmata device has and how to populate pull-down menus or other
>>> GUI widgets with only the appropriate choices.
>>> Maybe this could be Firmata 2.2 ? Maybe this is all a bit
>>> premature, since my hardware abstraction stuff is still in alpha
>>> Throughout its 18-year history, RSA Conference consistently attracts
>>> world's best and brightest in the field, creating opportunities for
>>> attendees to learn about information security's most important
>>> issues through
>>> interactions with peers, luminaries and emerging and established
>>> Firmata-devel mailing list
> "We have nothing to fear from love and commitment." - New York Senator
> Diane Savino, trying to convince the NY Senate to pass a gay marriage