Pin-mapping (non)conventions for custom Arduino boards?

Hi,
I've been working on an Arduino (Sanguino)-based extreme low-power + energy harvesting board, test version available here until I get a google code repository set up.

Playing with some of the Arduino libraries that would be most relevant to it, I ran into an issue with the new SD library that comes standard with Arduino since 0022: almost all the pin numbers are hardcoded in the library! I.e, without even the option to use different pins / non commercially made I/O shield. I could understand this in "some guy's" library written for a specific pet project and put online as an afterthought, but I wasn't really expecting it in officially supported libraries. Is this a common practice in the major libraries?

Likewise, should I assume major libraries make other assumptions, such as any GPIOs used by the library all residing on the same physical port, or Arduino pin numberings (in multiples of 8) mapping 1:1 with GPIO port bits? (e.g. Arduino pin # 8~15 = PORTB[0:7] OK, pin # 8~15 = PORTB[2:0], PORTC[5:1] not OK)

I didn't even consider this possibility when assigning pins; I had ass-umed the whole purpose of Arduino's pin-numbering abstraction (digitalWrite, etc.) was to free users from having to know or care how the numeric values marked on the board map to phyiscal GPIO port/pins, and free designers from having to copy the most popular guy's pinout to stay compatible. Is the SD library an isolated case / potentially a bug report, or would I be well advised to copy Sanguino / other board's pin mappings for a future / 'final' version?

A bunch of the libraries use the HW peripherals of the AVR chip (ie the SD library uses the SPI peripheral), and these are tied to specific pins of the chip, causing Arduino's nice abstraction of pin numbers to be ineffective.

Yes, I understand hardware peripheral functions are tied to specific AVR pins by design :stuck_out_tongue: I am referring specifically to GPIOs. Specifically, in the SD library's SD2PinMap.h, there is a bunch of code like:

#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
// Mega

// Two Wire (aka I2C) ports
uint8_t const SDA_PIN = 20;
uint8_t const SCL_PIN = 21;

// SPI port
uint8_t const SS_PIN = 53;
uint8_t const MOSI_PIN = 51;
uint8_t const MISO_PIN = 50;
uint8_t const SCK_PIN = 52;

static const pin_map_t digitalPinMap[] = {
  {&DDRE, &PINE, &PORTE, 0},  // E0  0
  {&DDRE, &PINE, &PORTE, 1},  // E1  1
  {&DDRE, &PINE, &PORTE, 4},  // E4  2
  {&DDRE, &PINE, &PORTE, 5},  // E5  3
  {&DDRG, &PING, &PORTG, 5},  // G5  4
  {&DDRE, &PINE, &PORTE, 3},  // E3  5
[...]

If I understand it correctly, the lib "tries to" use the hardware peripheral (e.g. if SOFTWARE_SPI is not defined...I ass-ume this is defined by libs such as NewSoftSerial maybe???), but the hardcoded GPIO identifier is used for initially setting the pins' states, or when SOFTWARE_SPI defined. The large structure following it I understand to be part of a speed-hack vs. digitalWrite(...), but these still limit portability to other boards or a configuration (e.g. hand-soldered SD socket) that does not match the unpublished assumption of "Arduino Pin Numbers" for a particular CPU.

I guess the latter structure answers my other question; "Arduino Pin Number" vs. port/bit seem to be in no particular order. For someone rolling my own board that I hope other people will use someday, my big question is how common this practice is among 'major' Arduino libraries - i.e. whether I should just crib the pin numberings from e.g. Sanguino (even if it turns my PCB traces into spaghetti) rather than "innovate" in this area :slight_smile: Or if I don't, to what extent I will have to petition library authors to include an #ifdef for my board that comparatively few people will use, and/or maintain my own forks of various libraries with the pin numbers changed / settable in constructor.

Thanks!

I think it's common for libraries to have even less pin mapping flexibility than the SD library...
For example, I believe that the Ethernet Shield library didn't work at all on Arduino Mega.

"Arduino Pin Number" vs. port/bit seem to be in no particular order.

Basically correct, I think. MEGA grouped PWM and "communications" pins together on the board, rather than trying to maintain a "pins from a particular port are grouped together."

I believe that more recent versions of the software are attempting to formalize pin mapping functions to a larger extent, so that it won't be necessary for libraries to include their own pin-mapping tables in order to implement "fast" versions of bit IO. That would mean you'd only need to provide new "core" functions rather than have each library modified. IFF the libraries are updated...

But in general, the libraries are going to divide into those that fully support the pin abstractions, and those that don't and would need to be customized for any departure from their original target board pinouts.

and/or maintain my own forks of various libraries with the pin numbers changed / settable in constructor.

That might be a bugger to maintain, although if it's just a few tables you could diff the files when there's a new official release, one wouldn't expect too many changes until a new board comes out.

"Arduino Pin Number" vs. port/bit seem to be in no particular order.

I noticed that on a Mega clone I'm designing, I've done my own (much more logical :)) pinout, but then my board is not physically compatible so it's less important.


Rob

Sounds like we're in about the same boat. I figured there wasn't much sense trying to keep shield-compatible an official (Arduino, Sanguino) board since the vast majority of shields aren't designed with power management provisions (no need to, since the Arduino pulls ~17mA idle on its own) - so while I'm doing my own thing, I decided to make it perfboard-friendly (leave that funny header spacing behind) and split the headers into 3 sections with the common bus signals (e.g. SPI, I2C, power/gnd) replicated for each.

Some libraries may have to be tweaked anyway (SD lib won't initialize a card more than once; necessary when cutting its power during idle periods), but hopefully they are in the minority!

maintain my own forks of various libraries with the pin numbers changed / settable in constructor.

Yeah, I feel your pain. IMO, all pin assignments should be given in the constructor. The biggest annoyance here to me is libraries hard-coding their SPI chip select pin. I find myself refactoring libraries all the time to account for this. Not sure if it's too late for this, but I would really advocate for Arduino to pick up that standard.

Some libraries may have to be tweaked anyway .........

This is definately true!
Usually you may also not find serious error handling, an absolute 'no go' for reliable software, but tolerable for hobby applications.
That what Arduino was designed for!

Defining a new GPIO-Pinout will not prevent users selecting boards like the mosquino.
If users share there tweakened libs with the cummunity, mosquino will be an serious tool.
But why not use it with AVR-Studio and some reliable and tested libraries/drivers for the ATMega family ....
The Arduino Software was never intended for use in commercial/critical projects!

The 'three port' solution that mosquino uses, allows als an dedicated shield for debugging porposes via the JTAG Interface if this is necessary.

And .... evolutionary changes of technical concepts will usually bring some benefit for the user or software developer :wink:

I guess most of the library were written for a specific situation at the first place.
Few years back when I was writing library for PIC microcontroller, the library always have options like:

  • Hardware or software based peripheral
  • Interrupt based or polling based
  • Which pin to use

But this of course take quite a long time to come out with a solid group of library for all peripheral and interface.
IMHO, there should be like a framework or skeleton body how a library should be in order for everyone who wish to write libraries.