[Answered]How to find port addresses for a given pin?

Ok, so I guess I will be flamed for this, but how can I use portOutputRegister(), digitalPinToPort() and digitalPinToBitMask() to find the actual port address of a pin, and then print it to serial monitor?

For example, looking at a .elf file I can see that DUE pin 26 is peripheral address 0x400e1234, how can I print these addresses in serial monitor just by providing the pin number?

Alternatively, where in the datasheet can I find this information? The SAM3x8E datasheet I have only goes as far as base address for PortC being 0x400e12xx.

This may be trivial to some of you, but it is beyond me apparently :-[ .

Any/all help much appreciated!

Regards,

Graham

The SAM3X data sheet is THE source of information on mapping of all internal registers. You have to take the time required to read and fully understand the pertinent sections.

Regards,
Ray L.

It appears what Ray actually meant was, 'you should look at about page 631 onwards of the datasheet', and is a reminder of why I don't usually ask for any help on this forum, preferring to give help when I can!

Regards,

Graham

1 Like

Look into schematic of the DUE board,

you will find association between pin number and port , ex. pin35 - PC3. After that point use data sheet. It's not clear why do you need address, usually PC3 is sufficient to map/address all registers, AFAIK atmel's ASF - build into arduino core files , takes care to find a correct reference offset.

The Arduino core provides a macro "digitalPinToPort(pin)" that should do what you want. It's in
.../packages/arduino/hardware/sam/1.6.5/variants/arduino_due_x/variant.h

Note that this is the address of the "PIO" controller associated with that pin, which contains a bunch of additional structure, AND controls up to 32 pins.
There are other useful macros as well.

#define digitalPinToPort(P)        ( g_APinDescription[P].pPort )
#define digitalPinToBitMask(P)     ( g_APinDescription[P].ulPin )
#define portOutputRegister(port)   ( &(port->PIO_ODSR) )
#define portInputRegister(port)    ( &(port->PIO_PDSR) )

These are the sorts of things that library writers use to "bit-bang" protocols at a higher speed than would be possible using digitalWrite(), without losing the arduino-style pin numbering. See also: digitalWrite() is embarassingly slow on Due... · Issue #4030 · arduino/Arduino · GitHub

westfw:

#define digitalPinToPort(P)        ( g_APinDescription[P].pPort )

#define digitalPinToBitMask(P)     ( g_APinDescription[P].ulPin )
#define portOutputRegister(port)   ( &(port->PIO_ODSR) )
#define portInputRegister(port)    ( &(port->PIO_PDSR) )




These are the sorts of things that library writers use to "bit-bang" protocols at a higher speed than would be possible using digitalWrite(), without losing the arduino-style pin numbering. See also: https://github.com/arduino/Arduino/issues/4030

That is exactly why I wanted the information, which I intend to use for my first shaky steps into in-line assembly for the purpose of trying to speed up UTFT.

I was wondering if there was any value in trying to replace :-

#define cbi(reg, bitmask) *reg &= ~bitmask
#define sbi(reg, bitmask) *reg |= bitmask

#define pulse_high(reg, bitmask) sbi(reg, bitmask); cbi(reg, bitmask);
#define pulse_low(reg, bitmask) cbi(reg, bitmask); sbi(reg, bitmask);

with in-line assembler? The resulting code in the .elf file looks a bit long winded and I wondered if it was possible to do this more efficiently manually?

Thanks Magician and westfw!

Regards,

Graham

Check out ADAFRUIT_TFTLCD library, there is a file pin_magic.h, worth to study.

Last time I was using direct port manipulation for bit-banging I2C, with something like:

void Set_DataLineDn(void)
{
    PIOB->PIO_MDER |= PIO_PB12;
    PIOB->PIO_CODR |= PIO_PB12;
    PIOB->PIO_OWER |= PIO_PB12;
    PIOB->PIO_OER  |= PIO_PB12;
}

void Set_DataLineIn(void)
{
    PIOB->PIO_IFER |= PIO_PB12;
    PIOB->PIO_ODR  |= PIO_PB12;
}

void Set_ClockLineDn(void)
{
    PIOB->PIO_MDER |= PIO_PB13;
    PIOB->PIO_CODR |= PIO_PB13;
    PIOB->PIO_OWER |= PIO_PB13;
    PIOB->PIO_OER  |= PIO_PB13;
}

void Set_ClockLineIn(void)
{
    PIOB->PIO_IFER |= PIO_PB13;
    PIOB->PIO_ODR  |= PIO_PB13;
}

As you can see, port name PB13 & PB12 is o'k to drive a pin, exact 0xXXXXXXXX address compiler would substitud at compile time

I was wondering if there was any value in trying to replace <> with in-line assembler?

I don't think so. I've programmed the ARMs in assembler, and I've looked at the digitalWrite() code. The ARM lacks any special-purpose bitset/clear instructions, and the compiler is pretty smart. You can save some time by factoring the digitalPinToPort(P)/digitalPinToBitMask out of a loop or saving them, and you might save some time by making sure that your bit sets are all grouped by port, but there are not likely to be any savings by going to assembler rather than C.

Um. There is "bit banding" on Due. I don't think that it will end up quicker than using the SODR/CODR registers in general, but there might be some circumstances where it would save an instruction or two.