GPIO managed with registers not working

Hi,
I'm using the registers to manage I/O on a Nano Every.

-My code was working using digitalWrite()
-My code doesn't work when changing to PORTn.OUTSET |= PINx_bm ;
-My code works again with register as described on line above if I put one digitalWrite() to any unused pin anywhere in the loop() code...

maybe I forgot something?

  PORTC.DIRSET |= PIN6_bm ; //in setup

  PORTC.OUTSET |= PIN6_bm ; //in loop

any idea?

My first suggestion is to post some of the code, mainly the setup() and the part of the loop[() that manipulates the port. Try this link first, it may answer your question: Arduino - PortManipulation

I believe with DIRSET and OUTSET you should use '=' and not '|='

e.g. PORTC.OUTSET = PIN6_bm ;

right, I've just noticed that, I experienced strange behaviour after modifying PORTE (PE1), which also contains arduino pin 13 with builtin LED (PE2). The led intensity was very low.

setup() {
  //IN
  PORTE.DIRCLR |= PIN1_bm ; //Arduino pin 12 as input WRONG!!!
  PORTE.DIRCLR = PIN1_bm ;
}

Can someone explain why? Maybe I don't get how SET and CLR registers work.

anyway, I changed all the _set and _clr, but still not working.

I can copy some code, but it's a 250 lines code perfectly working, except this strange issue.

From the datasheet:

So, you only write a '1' to the bit that you want to set or clear. Write a '0' to all others.

Just create a minimal but complete sketch which illustrates the problem and post that.

EDIT

The read part of this operation:

PORTE.DIRCLR |= PIN1_bm ; //Arduino pin 12 as input WRONG!!!

will return a 1 for each pin defined as an OUTPUT pin.
The write part of this operation will then set all those OUTPUT pins to INPUT because that is how DIRCLR reacts to a 1

but this should work:
PORTE.DIRCLR = PIN1_bm ;

Check page 143 of datasheet.
http://ww1.microchip.com/downloads/en/DeviceDoc/ATmega4808-4809-Data-Sheet-DS40002173A.pdf

In these newer AVRs, the PORT registers are

DIR
DIRSET
DIRCLR

OUT
OUTSET
OUTCLR

You use the "|=" for the OUT and DIR registers since those affect the whole byte (much like the old DDRx or PORTx)

The DIRSET/ OUTSET/OUTCLR/etc only affect the bit mask you are providing

PORTA.OUTSET = PIN0_bm | PIN1_bm would only affect bit0 and bit1 which in my opinion is a lot more readable than PORTA.OUT |= PIN0_bm | PIN1_bm

If the bitmask coding with same as traditional AVR is acceptable, the VPORT register provides faster direct port access.

But if you don't want assembly-level optimizations, it's very likely that you're fine to don't use it.
Well, I don't think it's a bad thing to should know.

thank you for your help and suggestions!
No, I don't really need assembly level optimizations, I could even use Arduino digitalWrite(), but in my first Arduino course I learned to use registers (old DDR / PORTx).
SET / CLR seems counter intuitive to me, since

DIRSET:
00000000 |
00000010 = 
00000010

as

PORTx.DIRSET = PIN1 ;
also equals
00000010

depends of the state of DIRSET before operation, but I read in the doc it is same as DIR.
Chapter 5.4 of AT4809 doc:

Registers with SET/CLR/TGL suffix allow the user to clear and set bits in a register without doing
a read-modify-write operation.
Each SET/CLR/TGL register is paired with the register it is affecting. Both registers in a register
pair return the same value when read.
Example: In the PORT peripheral, the OUT and OUTSET registers form such a register pair. The
contents of OUT will be modified by a write to OUTSET. Reading OUT and OUTSET will return
the same value.
Writing a ‘1’ to a bit in the CLR register will clear the corresponding bit in both registers.
Writing a ‘1’ to a bit in the SET register will set the corresponding bit in both registers.
Writing a ‘1’ to a bit in the TGL register will toggle the corresponding bit in both registers.

Sorry for this outer topic clarification, I'll try to reproduce my issue in a simple code soon.

Think of it as a sketch, running down from top to bottom.
The value of PORTD.DIR register is change on every line.
The value after being changed by that line is displayed in the comment.

PORTD.DIR  =  0b00000011;
/* Currently actual value is : 0b00000011 */

PORTD.DIR |=  0b11110000;
/* Currently actual value is : 0b11110011 */

PORTD.DIR &= ~0b00000011;
/* Currently actual value is : 0b11110000 */

PORTD.DIRSET = 0b00001100; // means PORTD.DIR |=  0b00001100;
/* Currently actual value is : 0b11111100 */

PORTD.DIRCLR = 0b00110000; // means PORTD.DIR &= ~0b00110000;
/* Currently actual value is : 0b11001100 */

The "means" comment indicates only that the C code has the same meaning.
The compiled assembly is different.
Since it is not read modify write, it is a little faster to use SET/CLR.

PORTx.DIRSET = PIN1_bm ; simply acts on the specified bit

PORTx.DIRSET |= PIN1_bm ; has the net effect of acting on the specified bit (but should not be used)

PORTx.DIRCLR = PIN1_bm ; simply acts on the specified bit

PORTx.DIRCLR |= PIN1_bm ; makes a mess because it clears previous definitions

EDIT

Code sample:

void setup() {

  Serial.begin( 115200 ) ;
  Serial.println() ;
  delay(1000);
  
  PORTE.DIRSET = PIN2_bm ;  // LED;  equivalent: pinMode( 13, OUTPUT )

  Serial.println(" led blinks 3 times " ) ;
  for ( int i = 0 ; i < 3 ; i++ )  {
    PORTE.OUTSET = PIN2_bm ;  // LED ON: equivalent: digitalWrite( 13, HIGH )
    delay( 1000 ) ;
    PORTE.OUTCLR = PIN2_bm ;  // LED OFF: equivalent: digitalWrite( 13, LOW )
    delay( 1000 ) ;
  }

  // Now clear a different PORTE direction pin using a read-modify-write construct
  // and observe the side effect on the "LED" pin

  PORTE.DIRCLR |= PIN1_bm ;  // not the LED pin 

  Serial.println(" led now fails to blink 3 times " ) ;

  for ( int i = 0 ; i < 3 ; i++ )  {
    PORTE.OUTSET = PIN2_bm ;  // LED ON: equivalent: digitalWrite( 13, HIGH )
    delay( 300 ) ;
    PORTE.OUTCLR = PIN2_bm ;  // LED OFF: equivalent: digitalWrite( 13, LOW )
    delay( 300 ) ;
  }

  // Now put it all back
  PORTE.DIRSET = PIN2_bm ;  // LED;  equivalent: pinMode( 13, OUTPUT )

  // Now clear a different PORTE direction pin using direct assignment
  PORTE.DIRCLR = PIN1_bm ;  // not the LED pin

  Serial.println(" led blinks 3 times " ) ;

  for ( int i = 0 ; i < 3 ; i++ )  {
    PORTE.OUTSET = PIN2_bm ;  // LED ON: equivalent: digitalWrite( 13, HIGH )
    delay( 1000 ) ;
    PORTE.OUTCLR = PIN2_bm ;  // LED OFF: equivalent: digitalWrite( 13, LOW )
    delay( 1000 ) ;
  }
}

void loop() {}

ok thank you for this example.
I assume .DIR simply configure a register, while .DIRSET / CLR / TGL run an hardware "code" configuring that register?

Now I found the cause of my issue. i tried this code:

void setup() {
  PORTE.DIRSET = PIN2_bm ;
}
void loop() {
  // put your main code here, to run repeatedly:
  while (1) {
    PORTE.OUTSET = PIN2_bm ;
    delay(50) ;
    PORTE.OUTCLR = PIN2_bm ;
    delay(300) ;
  }
}

It works perfectly.
Then I put some part of my code to find the guilty one, and the Timers activation broke the program (the led remains on)

void setup() {
 PORTE.DIRSET = PIN2_bm ; 
 sei() ;
}

now if I add

void loop() {
digitalWrite(5,HIGH) ;
... //rest of the previous code
}

it's working again.

So I searched in the arduino libs the digitalWrite() function:
.../arduino-1.8.13/hardware/arduino/avr/cores/arduino/wiring_digital.c, line 138

void digitalWrite(uint8_t pin, uint8_t val)
{
	uint8_t timer = digitalPinToTimer(pin);
	uint8_t bit = digitalPinToBitMask(pin);
	uint8_t port = digitalPinToPort(pin);
	volatile uint8_t *out;

	if (port == NOT_A_PIN) return;

	// If the pin that support PWM output, we need to turn it off
	// before doing a digital write.
	if (timer != NOT_ON_TIMER) turnOffPWM(timer);

	out = portOutputRegister(port);

	uint8_t oldSREG = SREG;
	cli();

	if (val == LOW) {
		*out &= ~bit;
	} else {
		*out |= bit;
	}

	SREG = oldSREG;
}

I'm particularly interested in PWM part...

Are you saying that this sketch fails in your environment ?

void setup() {
  PORTE.DIRSET = PIN2_bm ;
  sei() ;
}
void loop() {
  // put your main code here, to run repeatedly:
  while (1) {
    PORTE.OUTSET = PIN2_bm ;
    delay(50) ;
    PORTE.OUTCLR = PIN2_bm ;
    delay(300) ;
  }
}

It works for me.
Or post the exact sketch which fails so the problem is reproducible.

yes, this exact sketch fails: builtin led remains lit
IDE 1.8.13, Nano Every official, no emulation...

I can't reproduce the problem with the sketch in post #14 which I find unsurprising because sei(), especially in setup(), seems harmless:
IDE version: 1.8.16
Arduino Mega AVR boards core: 1.8.5
IDE option Register emulation: both None and ATmega328p

Maybe try with the version of the Arduino Mega AVR boards core I have used. Change it in Boards Manager.

right!
On IDE 1.8.13:
-I downgraded board core to 1.8.5 (was 1.8.7): it works for both my project code and the example above.
After update to latest 1.8.16 IDE:
-it works for both with core 1.8.5
-it works for the debug example with 1.8.7, but not with my project code
?!

ok, I made some tests, and it seems a bit random...
now the test code works even with sei(). But this one doesn't:

void setup() {
  PORTE.DIRSET = PIN2_bm ;
  
  TCA0.SINGLE.INTCTRL = TCA_SINGLE_OVF_bm ; //interruption sur overflow 
}
void loop() {
  while (1) {
    PORTE.OUTSET = PIN2_bm ;
    delay(50) ;
    PORTE.OUTCLR = PIN2_bm ;
    delay(300) ;
  }
}

Without looking into the Nano Every core, I'd suggest that your configuration of the timer has interfered with operation of the delay() function.
Check which timers are free if you need to use one explicitly.

how can I check?
I use RTC timer for second count and TCA0 for display (multiplex to 6 segments digits)