pointers to digital ports and xor

Hi guys.

I've implemeted some sort of digital signal generator on a uno and nano every and it works quite well. When I try to optimise stuff I get some problems though.

1.) My digi out pins are on both PORTB and PORTD so in my loop i have to differentiate. Instead of doing something like

if (PinOut[I].portID == 0) PORTB = 0x25;
else PORTD = 0x25;

It would be much nicer to have a pointer to PORTB or D and just write on *pPort... Now I did quite some research and found many examples like

volatile uint_t * const pPort = &PORTD;

But, well, I don't know if that ever worked, but it definitely doe not work for me, it keeps telling me "cannot convert 'PORTDClass*' to 'volatile byte* {aka volatile unsigned char*}' in initialization". (or something similar, no standard type works for me) Now I could define a PORTDClass* pPort but that does not work when writing on PORTB...

Is there any way?

2.) I want to toggle a PIN by doing a PORTB ^= bitMask; No chance: no match for 'operator^=' (operand types are 'PORTBClass' and 'char')

Ok, so the = operator is overloaded but ^= is not, fine, but PORTB = PORTB ^ bitMask gives a similar error msg. What is funny about this is this arduino reference page https://www.arduino.cc/reference/de/language/structure/bitwise-operators/bitwisexor/ that at the bottom tells me PORTB = PORTB ^ bitMask should be ok.

Any ideas on that?

Thanks Chris

edit: italics removed

Compiles, untested.

  uint8_t bitMask = 0b00110101;
  volatile uint8_t *ptr = &PORTB;
  noInterrupts();
  *ptr ^= bitMask;
  interrupts();

Since the read-modify-write is non-Atomic, I put it in a Critical Section.

Instead of doing something like

if (PinOut[I].portID == 0) PORTB = 0x25;

else PORTD = 0x25;






It would be much nicer to have a pointer to PORTB or D and just write on *pPort...
Now I did quite some research and found many examples like


volatile uint_t * const pPort = &PORTD;

If you’re “optimizing”, you might want to check whether using the pointer is actually faster than using the if. Pointers to io registers are not particularly fast on AVRs.

Also, you can invert port pins on most AVRs by writing to the PIN register:

if (PinOut[I].portID == 0) PINB = 0x25;  // invert some bits
   else PIND = 0x25;  // invert bits in OTHER port.

(which avoids the atomicity issue gfvalvo likes to bring up…)

gfvalvo:
Compiles, untested.

volatile uint8_t *ptr = &PORTB;

Thanks for the input. Yeah, “optimising” might make it worse…

Anyhow, exactly this line above gives me a “error: cannot convert ‘PORTBClass*’ to ‘volatile uint8_t* {aka volatile unsigned char*}’ in initialization volatile uint8_t *ptr = &PORTB;
volatile uint8_t ptr = PORTB; doesn’t work either.

Is there a compile switch or something I’d have to set?

Doing anything with PINB gives me a “‘PINB’ was not declared in this scope

Let's se the complete code and the complete error message.

Ah.. nano every doesn’t have “ports” - it has PORT simulation...

Edit: Not a complete statement. You can turn the "Registers Emulation" off in the tools menu (and you should probably do so, if you are at all concerned with efficiency. Also, it looks like it's supposed to do mapping from the (relatively logical) ATmeg328p pins to the (scrambledish) 4809 boards.

This would change the definition of PORTB from 'PORTBClass*' to '*(PORT_t *)', which still won't behave the way it does on the older AVRs.

You have two choices. One is the VPORTs, which behave like the old ports, more or less. You'd want something like:

volatile uint8_t *outptr = &(VPORTB.OUT);
volatile uint8_t *tglptr = &(VPORTB.IN);
volatile uint8_t *ddrptr = &(VPORTB.DIR);

The other is the new-style PORT_t style (AFTER you've turned off emulation), where you'd end up with:

// (make sure atmega328p emulation is turned off first!)
volatile uint8_t *outptr = &(PORTB.OUT);
volatile uint8_t *tglptr = &(PORTB.OUTTGL);
volatile uint8_t *inptr = &(PORTB.IN);
volatile uint8_t *ddrptr = &(PORTB.DIR);
// And many more options, like OUTCLR, OUTSET, DIRCLR, DIRSET...