Why volatile cannot be pass-by-reference

I have the following code, its compile with error “binding ‘volatile uint8_t {aka volatile unsigned char}’ to reference of type ‘const uint8_t& {aka const unsigned char&}’ discards qualifiers”

if I remove const from refrence port = 1 then I get error “invalid initialization of non-const reference of type ‘uint8_t& {aka unsigned char&}’ from an rvalue of type ‘uint8_t {aka unsigned char}’”

if I remove volatile and reference from port variable declaration its compile correct

#include <avr/wdt.h>

volatile uint8_t &portd = PIND;      //interrupts port
const uint8_t pinint0 = 1 << INT0;   //pin INT0

void soft_reset(const uint8_t wdt_prescale, const uint8_t &port = 1, const uint8_t pin = 1){
   wdt_enable(wdt_prescale);
   while(port & pin);
   wdt_disable();
}

void isPIRHigh(const uint8_t &port, const uint8_t pin){
   soft_reset(WDTO_8S, ~port, pin);               //finish when PD0 high
}

void isPIRLow(const uint8_t &port, const uint8_t pin){
   soft_reset(WDTO_8S, port, pin);                  //finish when PD0 low
}

void isPIRAlive(){
   isPIRHigh(portd, pinint0);
   isPIRLow(portd, pinint0);
}

void setup(){isPIRAlive();}

please help how I can change syntax of this code to pass validate of compilation

I don’t think it makes any sense to talk about a parameter being ‘volatile’ and then trying to give it a constant default value. Get rid of the default and it will compile.

#include <avr/wdt.h>

volatile uint8_t &portd = PIND;      //interrupts port
const uint8_t pinint0 = 1 << INT0;   //pin INT0

void soft_reset(const uint8_t wdt_prescale, volatile uint8_t &port, const uint8_t pin = 1) {
  wdt_enable(wdt_prescale);
  while (port & pin);
  wdt_disable();
}

void isPIRHigh(volatile uint8_t &port, const uint8_t pin) {
  soft_reset(WDTO_8S, port, pin);               //finish when PD0 high
}

void isPIRLow(volatile uint8_t &port, const uint8_t pin) {
  soft_reset(WDTO_8S, port, pin);                  //finish when PD0 low
}

void isPIRAlive() {
  isPIRHigh(portd, pinint0);
  isPIRLow(portd, pinint0);
}

void setup() {
  isPIRAlive();
}

void loop() {
}

volatile is used for variables which con be changed by the ISR Your var can't/won't be changed and there for should not be volatile

Mark

holmes4:
volatile is used for variables which con be changed by the ISR

That’s a partial but incomplete answer, and not applicable to this case. ‘volatile’ forces the compiler to create code that always accesses the memory location rather than relying on a copy of the value cached in a register.

Getting proper interaction between ISR and non-ISR code is one application of this.

However, another is access to memory-mapped registers. OP is trying to create a reference to the PIND register. If you take the time to trace through the definition of PIND, you’ll find that it's:

(*(volatile uint8_t *)(0x29))

Since it obviously makes no sense to use a cached value of an I/O port, ‘volatile’ is required.

gfvalvo:
However, OP is trying to create a reference to the PIND register.

yes. because in

while(port & pin);

I need to check real at this moment (not cached) value for port D, which it is expected to be changed. otherwise while never stops, verifying non changeable value.
According to your answer, I see that to use volatile in my case is correct. that good. so need to resolve issue with default value...

gfvalvo, I read, but forgot where, something like this.. we can make default value by pre declaration function at the top. like func (default value); if Im not wrong. I forget how was exactly.

void soft_reset(uint8_t port = 1, uint8_t pin = 1);

and after that in the middle of the code
will be my func

void soft_reset(const uint8_t wdt_prescale, volatile uint8_t &port, const uint8_t pin) 
{ ...code here... }

can I make like this ?

volatile can be passed by reference. You just need the right kid of reference. The language does allow you to discard cv-qualifiers when passing by reference or by pointer. You cannot discard const. You cannot discard volatile. If you want to pass a volatile object by reference, the reference has to be to volatile as well

volatile uint8_t &some_port = PIND;

void some_function(const volatile uint8_t &port)
{
  ...
}

...
some_function(some_port); // <-- No problems here

However, as you correctly noted yourself, you will not be able to bind a const volatile reference to a temporary object, e.g. your default argument. You can try to work around this limitation by using function overloading, but is looks like you are trying to solve some XY problem.

For example, what you have here

void isPIRHigh(const uint8_t &port, const uint8_t pin){
   soft_reset(WDTO_8S, ~port, pin);               //finish when PD0 high
}

is broken as well. You will not be able to pass ~port expression as a const volatile reference. This is also an attempt to bind that reference to a temporary value, which is not allowed.

alexblade:
gfvalvo, I read, but forgot where, something like this.. we can make default value by pre declaration function at the top. like func (default value); if Im not wrong. I forget how was exactly.

void soft_reset(uint8_t port = 1, uint8_t pin = 1);

and after that in the middle of the code
will be my func

void soft_reset(const uint8_t wdt_prescale, volatile uint8_t &port, const uint8_t pin) 

{ ...code here... }




can I make like this ?

No, I told you it makes no sense. Why do you insist on having a default value for the port? What could a port of "1" possibly mean?

If for some reason you absolutely have to have a default for the port parameter, at least use something that makes sense. This compiles:

#include <avr/wdt.h>

void soft_reset(const uint8_t wdt_prescale, volatile uint8_t &port = PIND, const uint8_t pin = 1) {
  wdt_enable(wdt_prescale);
  while (port & pin);
  wdt_disable();
}

void setup() {
  soft_reset(1, PINB, 4);
  soft_reset(1, PINC);
  soft_reset(1);
}

void loop() {
}

ok, as I understand , I have two issues at the moment
one is
a) how to declare/assign default value for const volatile uint8_t &port, and looks like it can be resolved by function overloading

and the second one more important
b) soft_reset(WDTO_8S, ~port, pin); I cannot send ~port as const volatile


the second one is worked beautiful when I used it as simple temporary value.... hm...

gfvalvo, " What could a port of "1" " - I can change to 255, 0b11111111

it used only for that case when we call soft_reset() w/o all arguments and in this case while() should be true. If I assign to &port=PORTD, it can be 0 and while not be true

PIND is already volatile!

Mark

gfvalvo, Montmorency
can I fix "default value issue" in the following mode

void soft_reset(const uint8_t wdt_prescale, const volatile uint8_t &port, const uint8_t pin){
	const volatile uint8_t &port_new = (port == NULL) ? 1 :  port;
	const uint8_t pin = (pin == NULL) ? 1 :  pin;
	const uint8_t wdt_prescale = (wdt_prescale == NULL) ? WDTO_15MS :  wdt_prescale;
   wdt_enable(wdt_prescale);
   while(port_new & pin);
   wdt_disable();
}

alexblade:
can I fix "default value issue" in the following mode

No, you can't.

But what do you think this does? What is your port == NULL supposed to check?

if we call soft_reset(WDTO_15MS);
the supposed
wdt_prescale = WDTO_15MS
&port = 1
pin = 1

after that we have
wdt_enable(WDTO_15MS); //15ms
while(1 & 1); //true

result: restart after 15ms //exact that I want when we call soft_reset w/o argument

The concept of a ‘const volatile’ just doesn’t make any sense to me. You’re making it much harder than it needs to be. You’ve dragged this on way longer than need. Just use function overloading like you mentioned previously:

#include <avr/wdt.h>

void soft_reset(const uint8_t wdt_prescale, volatile uint8_t &port, const uint8_t pin = 1) {
  wdt_enable(wdt_prescale);
  while (port & pin) {}
  wdt_disable();
}

void soft_reset(const uint8_t wdt_prescale) {
  wdt_enable(wdt_prescale);
  while (1) {}
  wdt_disable();
}

void setup() {
  soft_reset(1, PINB, 4);
  soft_reset(1, PINC);
  soft_reset(1);
}

void loop() {
}

"use function overloading"
Thank you, I got it, I got this method. But I also should understand (to teach/ to know) why method post#11 is not good ?

gfvalvo:
The concept of a 'const volatile' just doesn't make any sense to me.

If you are looking at it as "const means, the value will be constant" then I'd agree. But 'const' means this value is not permitted to be changed by code. Take a status register for example. You want to read it, but writing to it wouldn't make any sense (except for clearing the status, but often status registers are read-only). By declaring the status register as 'const volatile' the compiler will throw an error, whenever you write to the variable (the register) and generate a memory access when reading from the variable. This will prohibit any writes to read-only memory locations.

LightuC:
If you are looking at it as "const means, the value will be constant" then I'd agree. But 'const' means this value is not permitted to be changed by code. Take a status register for example. You want to read it, but writing to it wouldn't make any sense (except for clearing the status, but often status registers are read-only). By declaring the status register as 'const volatile' the compiler will throw an error, whenever you write to the variable (the register) and generate a memory access when reading from the variable. This will prohibit any writes to read-only memory locations.

OK, I'll buy that. Thanks.

LightuC:
But 'const' means this value is not permitted to be changed by code. Take a status register for example.

exact what I meant

Gentleman, can I use this code, is this code applicable to avoid scenario when I try to const volatile argument send temporary default value (for more details please refer to post#1)

void soft_reset(const uint8_t wdt_prescale, const volatile uint8_t &port, const uint8_t pin){
	const volatile uint8_t &port_new = (port == NULL) ? 1 :  port;
	const uint8_t pin = (pin == NULL) ? 1 :  pin;
	const uint8_t wdt_prescale = (wdt_prescale == NULL) ? WDTO_15MS :  wdt_prescale;
   wdt_enable(wdt_prescale);
   while(port_new & pin);
   wdt_disable();
}

alexblade:
exact what I meant

Gentleman, can I use this code, is this code applicable to avoid scenario when I try to const volatile argument send temporary default value (for more details please refer to post#1)

void soft_reset(const uint8_t wdt_prescale, const volatile uint8_t &port, const uint8_t pin){
const volatile uint8_t &port_new = (port == NULL) ? 1 :  port;
const uint8_t pin = (pin == NULL) ? 1 :  pin;
const uint8_t wdt_prescale = (wdt_prescale == NULL) ? WDTO_15MS :  wdt_prescale;

wdt_enable(wdt_prescale);
  while(port_new & pin);
  wdt_disable();
}

No, it is not. The comparison port == NULL does not achieve anything close to what you want. It simply compares the uint8_t value of the port with NULL (which is typically 0). What is it doing here and why? Show us an example of how you expect to use it.

This is not even guaranteed to compile, since in modern C++ NULL can be defined as nullptr. And you are not allowed to compare integer values with nullptr. NULL is intended to be used in pointer contexts only. Don't use it in integer context - it makes no sense.